zoukankan      html  css  js  c++  java
  • 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)

    取板粗   好东西来的

    1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665

    (POJ2104)http://poj.org/problem?id=2104

    (POJ2761)http://poj.org/problem?id=2761

    题意:求区间第K大,主席树模板题

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=200010;
    int tot,n,q,nowm;
    int a[maxn],t[maxn];
    int c[maxn<<5],lson[maxn<<5],rson[maxn<<5];
    int T[maxn];
    
    void init_hash()
    {
        for ( int i=1;i<=n;i++ ) t[i]=a[i];
        sort(t+1,t+1+n);
        nowm=unique(t+1,t+1+n)-(t+1);
    }
    
    int hash_(int x)
    {
        return lower_bound(t+1,t+1+nowm,x)-t;
    }
    
    void build(int &root,int l,int r)
    {
        root=++tot;
        if ( l==r ) return;
        int mid=(l+r)/2;
        build(lson[root],l,mid);
        build(rson[root],mid+1,r);
    }
    
    void update(int root,int &rt,int p,int val,int l,int r)
    {
        rt=++tot;
        lson[rt]=lson[root],rson[rt]=rson[root];
        c[rt]=c[root]+val;
        if ( l==r ) return;
        int mid=(l+r)/2;
        if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid);
        else update(rson[rt],rson[rt],p,val,mid+1,r);
    }
    
    int query(int rt_,int rt,int l,int r,int k)
    {
        if ( l==r ) return l;
        int mid=(l+r)/2;
        int sum=c[lson[rt_]]-c[lson[rt]];
        if ( sum>=k ) return query(lson[rt_],lson[rt],l,mid,k);
        else return query(rson[rt_],rson[rt],mid+1,r,k-sum);
    }
    
    int main()
    {
        int Case;
        scanf("%d",&Case);
        while(Case++){
            scanf("%d%d",&n,&q);
            tot=0;
            for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
            init_hash();
            build(T[0],1,nowm);
            for ( int i=1;i<=n;i++ )
            {
                int pos=hash_(a[i]);
                update(T[i-1],T[i],pos,1,1,nowm);
            }
            while ( q-- )
            {
                int l,r,k;
                scanf("%d%d%d",&l,&r,&k);
                printf("%d
    ",t[query(T[r],T[l-1],1,nowm,k)]);
            }
        }
        return 0;
    }
    View Code

    2.(HDOJ4417)http://acm.hdu.edu.cn/showproblem.php?pid=4417

    题意:求给定区间<=k的数有多少

    分析:在模板上将query部分修改一下即可,对于区间[L,R]来说,只需要将第R颗线段树上的[0,k]区间内的值减去第L-1颗线段树上对应区间即可。离线在线都行,离线做法需要将每次访问的k也添加进入hash数组,而对于在线来说转化后的数转化前相对于给定的k来说只能变小不能变大即可

    注意:题目给的区间范围从0开始,要将其转化成从1开始

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=1e5+10;
    const int maxm=3e6+10;
    int n,q,m,tot;
    int a[maxn],t[maxn];
    int T[maxn],lson[maxm],rson[maxm],c[maxm];
    
    void init_hash()
    {
        for ( int i=1;i<=n;i++ ) t[i]=a[i];
        sort(t+1,t+1+n);
        m=unique(t+1,t+1+n)-(t+1);
    }
    
    int build(int l,int r)
    {
        int root=tot++;
        c[root]=0;
        if ( l!=r )
        {
            int mid=(l+r)/2;
            lson[root]=build(l,mid);
            rson[root]=build(mid+1,r);
        }
        return root;
    }
    
    int hash_(int x)
    {
        return lower_bound(t+1,t+1+m,x)-t;
    }
    
    int update(int root,int pos,int val)
    {
        int rt=tot++,tmp=rt;
        c[rt]=c[root]+val;
        int l=1,r=m;
        while ( l<r )
        {
            int mid=(l+r)/2;
            if ( pos<=mid )
            {
                lson[rt]=tot++;rson[rt]=rson[root];
                rt=lson[rt];root=lson[root];
                r=mid;
            }
            else 
            {
                rson[rt]=tot++;lson[rt]=lson[root];
                rt=rson[rt];root=rson[root];
                l=mid+1;
            }
            c[rt]=c[root]+val;
        }
        return tmp;
    }
    
    int query(int lrt,int rrt,int k)
    {
        int ret=0;
        int l=1,r=m;
        while ( l<r )
        {
            int mid=(l+r)/2;
            if ( k<=mid )
            {
                r=mid;
                lrt=lson[lrt];
                rrt=lson[rrt];
            }
            else 
            {
                ret+=c[lson[rrt]]-c[lson[lrt]];
                l=mid+1;
                lrt=rson[lrt];
                rrt=rson[rrt];
            }
        }
        ret+=c[rrt]-c[lrt];
        return ret;
    }
    
    int main()
    {
        int Case,h;
        scanf("%d",&Case);
        for ( h=1;h<=Case;h++ )
        {
            scanf("%d%d",&n,&q);
            tot=0;
            for ( int i=1;i<=n;i++ ) 
            {
                scanf("%d",&a[i]);
                a[i]++;
            }
            init_hash();
            T[0]=build(1,m);
            for ( int i=1;i<=n;i++ )
            {
                int pos=hash_(a[i]);
                T[i]=update(T[i-1],pos,1);
            }
            printf("Case %d:
    ",h);
            while ( q-- )
            {
                int l,r,k,p;
                scanf("%d%d%d",&l,&r,&k);
                l++,r++,k++;
                p=hash_(k);
                if ( t[p]>k ) p--;
                if ( p==0 ) printf("0
    ");
                else printf("%d
    ",query(T[l-1],T[r],p));
            }
        }
        return 0;
    }
    
    HDOJ4417(在线)
    在线
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=1e5+10;
    const int maxm=3e6+10;
    int n,q,m,tot;
    int a[maxn],t[maxn*2],l[maxn],r[maxn],val[maxn];
    int T[maxn],lson[maxm],rson[maxm],c[maxm];
    
    void init_hash()
    {
        for ( int i=1;i<=n;i++ ) t[i]=a[i];
        for ( int i=1;i<=q;i++ ) t[i+n]=val[i];
        sort(t+1,t+1+n+q);
        m=unique(t+1,t+1+n+q)-(t+1);
    }
    
    int build(int l,int r)
    {
        int root=tot++;
        c[root]=0;
        if ( l!=r )
        {
            int mid=(l+r)/2;
            lson[root]=build(l,mid);
            rson[root]=build(mid+1,r);
        }
        return root;
    }
    
    int hash_(int x)
    {
        return lower_bound(t+1,t+1+m,x)-t;
    }
    
    int update(int root,int pos,int val)
    {
        int rt=tot++,tmp=rt;
        c[rt]=c[root]+val;
        int l=1,r=m;
        while ( l<r )
        {
            int mid=(l+r)/2;
            if ( pos<=mid )
            {
                lson[rt]=tot++;rson[rt]=rson[root];
                rt=lson[rt];root=lson[root];
                r=mid;
            }
            else 
            {
                rson[rt]=tot++;lson[rt]=lson[root];
                rt=rson[rt];root=rson[root];
                l=mid+1;
            }
            c[rt]=c[root]+val;
        }
        return tmp;
    }
    
    int query(int lrt,int rrt,int k)
    {
        int ret=0;
        int l=1,r=m;
        while ( l<r )
        {
            int mid=(l+r)/2;
            if ( k<=mid )
            {
                r=mid;
                lrt=lson[lrt];
                rrt=lson[rrt];
            }
            else 
            {
                ret+=c[lson[rrt]]-c[lson[lrt]];
                l=mid+1;
                lrt=rson[lrt];
                rrt=rson[rrt];
            }
        }
        ret+=c[rrt]-c[lrt];
        return ret;
    }
    
    int main()
    {
        int Case,h;
        scanf("%d",&Case);
        for ( h=1;h<=Case;h++ )
        {
            scanf("%d%d",&n,&q);
            tot=0;
            for ( int i=1;i<=n;i++ ) 
            {
                scanf("%d",&a[i]);
                a[i]++;
            }
            for ( int i=1;i<=q;i++ ) {
                scanf("%d%d%d",&l[i],&r[i],&val[i]);
                l[i]++,r[i]++,val[i]++;
            }
            init_hash();
            T[0]=build(1,m);
            for ( int i=1;i<=n;i++ )
            {
                int pos=hash_(a[i]);
                T[i]=update(T[i-1],pos,1);
            }
            printf("Case %d:
    ",h);
            for ( int i=1;i<=q;i++ )
            {
                int L,R,k;
                L=l[i],R=r[i],k=val[i];
                k=hash_(k);
                printf("%d
    ",query(T[L-1],T[R],k));
            }
        }
        return 0;
    }
    
    HDOJ4417(离线)
    离线

    3.(SPOJ3267)http://www.spoj.com/problems/DQUERY/

    题意:给出一个长度为n 的数列,有q 个询问,每个询问给出数对 [i,j],需要你给出这一段中有多少不同的数字

    分析:利用map记录每个数的位置,主席树建新树的时候,如果当前元素出现过,那么把这个元素上次出现的位置减一,然后当前位置加一,如果没出现过就是普通的建树操作。

    对于查询[l, r]我们只需要取出第r棵树,然后输出这棵树[l,r]之间的和,因为是按从1到n的顺序插入的,所以每次只需要求>=l的个数即可

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    using namespace std;
    const int maxn=3e4+10;
    const int maxm=3e6+10;
    int n,q,tot;
    int a[maxn];
    int T[maxn],lson[maxm],rson[maxm],c[maxm];
    
    int build(int l,int r)
    {
        int root=tot++;
        c[root]=0;
        if ( l!=r )
        {
            int mid=(l+r)/2;
            lson[root]=build(l,mid);
            rson[root]=build(mid+1,r);
        }
        return root;
    }
    
    int update(int root,int pos,int val)
    {
        int rt=tot++,tmp=rt;
        c[rt]=c[root]+val;
        int l=1,r=n;
        while ( l<r )
        {
            int mid=(l+r)/2;
            if ( pos<=mid )
            {
                lson[rt]=tot++;rson[rt]=rson[root];
                rt=lson[rt];root=lson[root];
                r=mid;
            }
            else 
            {
                rson[rt]=tot++;lson[rt]=lson[root];
                rt=rson[rt];root=rson[root];
                l=mid+1;
            }
            c[rt]=c[root]+val;
        }
        return tmp;
    }
    
    int query(int rt,int lpos)
    {
        int ret=0;
        int l=1,r=n;
        while ( lpos>l )
        {
            int mid=(l+r)/2;
            if ( lpos<=mid )
            {
                r=mid;
                ret+=c[rson[rt]];
                rt=lson[rt];
            }
            else 
            {
                rt=rson[rt];
                l=mid+1;
            }
        }
        return ret+c[rt];
    }
    
    int main()
    {
        int Case;
        while ( scanf("%d",&n)!=EOF )
        {
            tot=0;
            for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
            T[0]=build(1,n);
            map<int,int>mp;
            for ( int i=1;i<=n;i++ )
            {
                if ( mp.find(a[i])!=mp.end() ) 
                {
                    int tmp=update(T[i-1],mp[a[i]],-1);
                    T[i]=update(tmp,i,1);
                }
                else T[i]=update(T[i-1],i,1);
                mp[a[i]]=i;
            }
            scanf("%d",&q);
            while ( q-- )
            {
                int l,r;
                scanf("%d%d",&l,&r);
                printf("%d
    ",query(T[r],l));
            }
        }
        return 0;
    }
    
    SPOJ3267
    View Code

    4.(ZOJ2112)http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112

    题意:给定一串序列,有两种操作,一种是求区间[l,r]第k大,另外一种是将a[i]=t

    带修改的主席树

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=60010;
    const int maxm=2500010;
    int n,q,m,tot;
    int a[maxn],t[maxn];
    int T[maxn],lson[maxm],rson[maxm],c[maxm];
    int S[maxn];
    struct Query{
        int kind;
        int l,r,k;
    }query[10010];
    
    void init_hash(int k)
    {
        sort(t+1,t+k+1);
        m=unique(t+1,t+k+1)-(t+1);
    }
    
    int hash_(int x)
    {
        return lower_bound(t+1,t+m+1,x)-t;
    }
    
    int build(int l,int r)
    {
        int root=tot++;
        c[root]=0;
        if ( l!=r )
        {
            int mid=(l+r)/2;
            lson[root]=build(l,mid);
            rson[root]=build(mid+1,r);
        }
        return root;
    }
    
    int update(int root,int pos,int val)
    {
        int rt=tot++,tmp=rt;
        c[rt]=c[root]+val;
        int l=1,r=m;
        while ( l<r )
        {
            int mid=(l+r)/2;
            if ( pos<=mid )
            {
                lson[rt]=tot++;rson[rt]=rson[root];
                rt=lson[rt];root=lson[root];
                r=mid;
            }
            else 
            {
                rson[rt]=tot++;lson[rt]=lson[root];
                rt=rson[rt];root=rson[root];
                l=mid+1;
            }
            c[rt]=c[root]+val;
        }
        return tmp;
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    int used[maxn];
    void add(int x,int pos,int val)
    {
        while ( x<=n )
        {
            S[x]=update(S[x],pos,val);
            x+=lowbit(x);
        }
    }
    
    int sum(int x)
    {
        int ret=0;
        while ( x>0 )
        {
            ret+=c[lson[used[x]]];
            x-=lowbit(x);
        }
        return ret;
    }
    
    int Q(int left,int right,int k)
    {
        int lrt=T[left];
        int rrt=T[right];
        int l=1,r=m;
        for ( int i=left;i>0;i-=lowbit(i)) used[i]=S[i];
        for ( int i=right;i>0;i-=lowbit(i)) used[i]=S[i];
        while ( l<r )
        {
            int mid=(l+r)/2;
            int tmp=sum(right)-sum(left)+c[lson[rrt]]-c[lson[lrt]];
            if ( tmp>=k )
            {
                r=mid;
                for ( int i=left;i>0;i-=lowbit(i)) used[i]=lson[used[i]];
                for ( int i=right;i>0;i-=lowbit(i)) used[i]=lson[used[i]];
                lrt=lson[lrt];
                rrt=lson[rrt];
            }
            else 
            {
                l=mid+1;
                k-=tmp;
                for ( int i=left;i>0;i-=lowbit(i)) used[i]=rson[used[i]];
                for ( int i=right;i>0;i-=lowbit(i)) used[i]=rson[used[i]];
                lrt=rson[lrt];
                rrt=rson[rrt];
            }
        }
        return l;
    }
    
    int main()
    {
        int Case;
        scanf("%d",&Case);
        while ( Case-- )
        {
            scanf("%d%d",&n,&q);
            tot=0;
            m=0;
            for ( int i=1;i<=n;i++ ) 
            {
                scanf("%d",&a[i]);
                t[++m]=a[i];
            }
            char op[10];
            for ( int i=0;i<q;i++ )
            {
                scanf("%s",op);
                if ( op[0]=='Q' )
                {
                    query[i].kind=0;
                    scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k);
                }
                else
                {
                    query[i].kind=1;
                    scanf("%d%d",&query[i].l,&query[i].r);
                    t[++m]=query[i].r;
                }
            }
            init_hash(m);
            T[0]=build(1,m);
            for ( int i=1;i<=n;i++ )
            {
                int pos=hash_(a[i]);
                T[i]=update(T[i-1],pos,1);
            }
            for ( int i=1;i<=n;i++ ) S[i]=T[0];
            for ( int i=0;i<q;i++ )
            {
                if ( query[i].kind==0 ) printf("%d
    ",t[Q(query[i].l-1,query[i].r,query[i].k)]);
                else 
                {
                    add(query[i].l,hash_(a[query[i].l]),-1);
                    add(query[i].l,hash_(query[i].r),1);
                    a[query[i].l]=query[i].r;
                }
            }
        }
        return 0;
    }
    
    ZOJ2112
    View Code

    5.(HDOJ4348)http://acm.hdu.edu.cn/showproblem.php?pid=4348

    题意:给出一段长度为n的序列,有4种操作。初始时,时间戳=0

    a.C l r d [l,r]区间内的数+d,时间戳++

    b.Q l r 求当前时间戳下[l,r]区间的和

    c.H l r t 求时间戳=t下[l,r]区间的和

    d.B t  时间戳=t

    分析:推荐两个讲解较为详细的博客https://blog.csdn.net/glqac/article/details/45103859

    https://blog.csdn.net/kirito16/article/details/47266801

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+10;
    const int maxm=3e6+10;
    int n,q,tot;
    int a[maxn];
    int T[maxn],lson[maxm],rson[maxm];
    ll sum[maxm],add[maxm];
    
    int build(int l,int r)
    {
        int root=tot++;
        add[root]=0;
        if ( l!=r )
        {
            int mid=(l+r)/2;
            lson[root]=build(l,mid);
            rson[root]=build(mid+1,r);
        }
        else
        {
            scanf("%lld",&sum[root]);
            return root;
        }
        sum[root]=sum[lson[root]]+sum[rson[root]];
        return root;
    }
    
    
    void pushup(int rt,int len)
    {
        sum[rt]=sum[lson[rt]]+sum[rson[rt]]+add[lson[rt]]*(len-len/2)+add[rson[rt]]*(len/2);
    }
    
    int A,B;
    ll val;
    
    int update(int root,int l,int r)
    {
        int rt=tot++;
        add[rt]=add[root];
        if ( A<=l && r<=B )
        {
            sum[rt]=sum[root];
            add[rt]=add[root]+val;
            lson[rt]=lson[root];
            rson[rt]=rson[root];
            return rt;
        }
        int mid=(l+r)/2;
        if ( A<=mid ) lson[rt]=update(lson[root],l,mid);
        else lson[rt]=lson[root];
        if ( B>mid ) rson[rt]=update(rson[root],mid+1,r);
        else rson[rt]=rson[root];
        pushup(rt,r-l+1);
        return rt;
    }
    
    ll query(int root,int l,int r,ll add_)
    {
        if ( A<=l && r<=B ) return sum[root]+(add_+add[root])*(r-l+1);
        ll ans=0;
        int mid=(l+r)/2;
        if ( A<=mid ) ans+=query(lson[root],l,mid,add[root]+add_);
        if ( B>mid ) ans+=query(rson[root],mid+1,r,add[root]+add_);
        return ans;
    }
    
    int main()
    {
        char op[5];
        int now,Case=0;
        while ( scanf("%d%d",&n,&q)!=EOF )
        {
            if ( Case!=0 ) printf("
    ");
            Case++;
            tot=0;
            T[0]=build(1,n);
            now=0;
            while ( q-- )
            {
                ll ans;
                int k;
                scanf("%s",op);
                if ( op[0]=='C' ) 
                {
                    scanf("%d%d%lld",&A,&B,&val);
                    T[now+1]=update(T[now],1,n);
                    now++;
                }
                else if ( op[0]=='Q' )
                {
                    scanf("%d%d",&A,&B);
                    ans=query(T[now],1,n,0); 
                    printf("%lld
    ",ans);
                }
                else if ( op[0]=='H' )
                {
                    scanf("%d%d%d",&A,&B,&k);
                    ans=query(T[k],1,n,0); 
                    printf("%lld
    ",ans);
                }
                else if ( op[0]=='B' ) 
                {
                    scanf("%d",&k);
                    now=k;
                    tot=T[now+1];
                }
            }
        }
        return 0;
    }
    
    HDOJ4348
    View Code
  • 相关阅读:
    MapBox TileMill
    优秀电影
    Mapnik 编译安装过程
    Debian 入门安装与配置2
    学习opengl十大网站(转载)
    PostgresSQL 学习资料记录处
    c++模板编程-异质链表
    Linux-统一事件源
    三组I/O复用模型的比较
    ZigZag-LeetCode
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9742271.html
Copyright © 2011-2022 走看看