zoukankan      html  css  js  c++  java
  • zoj2112 Dynamic Rankings (主席树 || 树套树)

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

    Your task is to write a program for this computer, which

    - Reads N numbers from the input (1 <= N <= 50,000)

    - Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.


    Input

    The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

    The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format

    Q i j k or
    C i t

    It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.

    There're NO breakline between two continuous test cases.


    Output

    For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])

    There're NO breakline between two continuous test cases.


    Sample Input

    2
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3


    Sample Output

    3
    6
    3
    6


    题意:给你一个长为n的区间,有m个询问和修改,每次把下标i对应的值改变,或者询问某段区间的第k小值。

    思路:这题是很经典的题,可以用主席树和树套树做,对于树套树的做法,我是用线段树的每一个节点都存一个treap,然后每一次修改就是单点更新,修改的时间复杂度为O(n*logn*logn),询问时,需要二分值val,并统计线段树中对应的区间小于val值的个数,询问的时间复杂度为O(n*logn*logn*logn),所以总的时间复杂度为O(n*logn*logn*logn),同时因为线段树最多有logn层,每层都是n个节点,所以treap的空间复杂度为O(n*logn).


    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<string>
    #include<bitset>
    #include<algorithm>
    using namespace std;
    #define lson th<<1
    #define rson th<<1|1
    typedef long long ll;
    typedef long double ldb;
    #define inf 99999999
    #define pi acos(-1.0)
    #define maxn 50005
    int rt[maxn*4],a[maxn],n;
    int cnt;
    struct Treap{
        int key,pri,siz,num,son[2];
        void newnode(int x,int y){
            key=x;pri=y;
            siz=num=1;
            son[0]=son[1]=0;
        }
    }T[20*maxn];
    
    
    void rotate(int p,int &x)
    {
        int y=T[x].son[!p];
        T[x].siz=T[x].siz-T[y].siz+T[T[y].son[p] ].siz;
        T[x].son[!p]=T[y].son[p];
        T[y].siz=T[y].siz-T[T[y].son[p] ].siz+T[x].siz;
        T[y].son[p]=x;
        x=y;
    }
    
    void charu(int key,int &x)
    {
        if(x==0){
            x=++cnt;
            T[x].newnode(key,rand());
        }
        else{
            T[x].siz++;
            if(T[x].key==key){
                T[x].num++;return;
            }
            int p=key<T[x].key;
            charu(key,T[x].son[!p]);
            if(T[x].pri<T[T[x].son[!p] ].pri )
                rotate(p,x);
        }
    }
    void del(int key, int &x)
    {
        if(T[x].key == key)
        {
            if(T[x].num>1){
                T[x].siz--;
                T[x].num--;
                return;
            }
            if(T[x].son[0] && T[x].son[1])
            {
                int p=T[T[x].son[0]].pri>T[T[x].son[1]].pri;
                rotate(p,x);
                del(key,x);
            }
            else x=T[x].son[1]+T[x].son[0];
        }
        else
        {
            T[x].siz--;
            int p=T[x].key>key;
            del(key,T[x].son[!p]);
        }
    }
    int query_rank(int key,int &x)
    {
        if(x==0)return 0;
        if(T[x].key==key)return T[T[x].son[0] ].siz;
        if(T[x].key>key)return query_rank(key,T[x].son[0]);
        if(T[x].key<key)return T[T[x].son[0] ].siz+T[x].num+query_rank(key,T[x].son[1]);
    }
    
    
    
    void update(int idx,int val,int L,int R,int th,int f)
    {
        if(f)del(a[idx],rt[th]);
        charu(val,rt[th]);
        if(L==idx && R==idx){
            a[idx]=val;
            return;
        }
        int mid=(L+R)/2;
        if(idx<=mid)update(idx,val,L,mid,lson,f);
        else update(idx,val,mid+1,R,rson,f);
    }
    
    
    int question(int l,int r,int val,int L,int R,int th)
    {
        int mid;
        if(l==L && r==R){
            return query_rank(val,rt[th]);
        }
        mid=(L+R)/2;
        if(r<=mid)return question(l,r,val,L,mid,lson);
        else if(l>mid)return question(l,r,val,mid+1,R,rson);
        else return question(l,mid,val,L,mid,lson)+question(mid+1,r,val,mid+1,R,rson);
    }
    
    int main()
    {
        int m,i,j,Tcase,l,r,c,d,e,mid;
        char s[10];
        scanf("%d",&Tcase);
        while(Tcase--)
        {
            memset(rt,0,sizeof(rt));
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            cnt=0;
            for(i=1;i<=n;i++){
                update(i,a[i],1,n,1,0);
            }
            for(i=1;i<=m;i++){
                scanf("%s",s);
                if(s[0]=='C'){
                    scanf("%d%d",&c,&d);
                    update(c,d,1,n,1,1);
                }
                else{
                    scanf("%d%d%d",&c,&d,&e);
                    l=0;r=1000000000;
                    while(l<=r){
                        mid=(l+r)/2;
                        //printf("%d %d %d
    ",l,r,mid);
                        if(question(c,d,mid,1,n,1)>=e)r=mid-1;
                        else l=mid+1;
                    }
                    printf("%d
    ",r);
                }
            }
    
        }
        return 0;
    }
    
    /*
    2
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    */
    

    主席树做法:

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<string>
    #include<bitset>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef long double ldb;
    #define lth th<<1
    #define rth th<<1|1
    #define inf 99999999
    #define pi acos(-1.0)
    #define maxn 60005
    #define M 2500010
    int a[maxn],n;
    struct node{
        int l,r,kind,d;
    }ques[10005];
    int pos[maxn],T[maxn],S[maxn];
    int lson[M],rson[M],c[M];
    int th,tot;
    
    int build(int l,int r)
    {
        int newroot=++th,i,j,mid;
        c[newroot]=0;   //!!!
        if(l!=r){
            mid=(l+r)/2;
            lson[newroot]=build(l,mid);
            rson[newroot]=build(mid+1,r);
        }
        return newroot;
    }
    
    int update(int root,int zhi,int value)
    {
        int i,j;
        int newroot=++th;int tmp=newroot;
        int l=1,r=tot,mid;
        c[newroot]=c[root]+value;
        while(l<r){
            mid=(l+r)/2;
            if(zhi<=mid){
                r=mid;
                lson[newroot ]=++th;rson[newroot]=rson[root];
                newroot=lson[newroot];root=lson[root];
            }
            else{
                l=mid+1;
                lson[newroot ]=lson[root];rson[newroot]=++th;
                newroot=rson[newroot];root=rson[root];
            }
            c[newroot]=c[root]+value;
        }
        return tmp;
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void modify(int pos,int zhi,int value)
    {
        int i,j;
        while(pos<=n){
            S[pos]=update(S[pos],zhi,value);
            pos+=lowbit(pos);
        }
    }
    int use[maxn];
    int getsum(int pos)
    {
        int sum=0;
        while(pos>0){
            sum+=c[lson[use[pos] ] ];
            pos-=lowbit(pos);
        }
        return sum;
    
    }
    int question(int left,int right,int k)
    {
        int i,j,root1,root2;
        int l=1,r=tot,mid;
        for(i=left-1;i>0;i-=lowbit(i))use[i]=S[i];
        for(i=right;i>0;i-=lowbit(i))use[i]=S[i];
        root1=T[left-1];root2=T[right];
    
        while(l<r){
            mid=(l+r)/2;
            int tmp=getsum(right)-getsum(left-1)+c[lson[root2] ]-c[lson[root1] ];
            if(tmp>=k){
                r=mid;
                root1=lson[root1];root2=lson[root2];
                for(i=left-1;i>0;i-=lowbit(i))use[i]=lson[use[i] ];
                for(i=right;i>0;i-=lowbit(i))use[i]=lson[use[i] ];
            }
            else{
                k-=tmp;
                l=mid+1;
                root1=rson[root1];root2=rson[root2];
                for(i=left-1;i>0;i-=lowbit(i))use[i]=rson[use[i] ];
                for(i=right;i>0;i-=lowbit(i))use[i]=rson[use[i] ];
            }
        }
        return l;
    }
    
    int main()
    {
        int m,i,j,Tcase,c,d,e;
        char str[5];
        scanf("%d",&Tcase);
        while(Tcase--)
        {
            scanf("%d%d",&n,&m);
            tot=0;
            for(i=1;i<=n;i++){
                scanf("%d",&a[i]);
                tot++;
                pos[tot]=a[i];
            }
            for(i=1;i<=m;i++){
                scanf("%s",str);
                if(str[0]=='Q'){
                    scanf("%d%d%d",&c,&d,&e);
                    ques[i].kind=0;ques[i].l=c;ques[i].r=d;ques[i].d=e;
                }
                else if(str[0]=='C'){
                    scanf("%d%d",&c,&d);
                    tot++;pos[tot]=d;
                    ques[i].kind=1;ques[i].l=c;ques[i].r=d;
                }
            }
    
            sort(pos+1,pos+1+tot);
            tot=unique(pos+1,pos+1+tot)-pos-1;
    
            th=0;
            T[0]=build(1,tot);
    
    
            for(i=1;i<=n;i++){
                int t=lower_bound(pos+1,pos+1+tot,a[i])-pos;
                T[i]=update(T[i-1],t,1);
            }
    
            for(i=1;i<=n;i++){
                S[i]=T[0];
            }
            for(i=1;i<=m;i++){
                if(ques[i].kind==0){   //表示询问
                    printf("%d
    ",pos[question(ques[i].l,ques[i].r,ques[i].d)]);
                }
                else{
                    int t1=lower_bound(pos+1,pos+1+tot,a[ques[i].l])-pos;
                    int t2=lower_bound(pos+1,pos+1+tot,ques[i].r)-pos;
                    modify(ques[i].l,t1,-1);
                    modify(ques[i].l,t2,1);
                    a[ques[i].l ]=ques[i].r;  //!!!
                }
            }
    
        }
        return 0;
    }
    
    /*
    2
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    */



  • 相关阅读:
    《代码整洁之道》三
    《代码整洁之道》二
    第五周总结
    第四周总结
    第三周总结
    第二周总结
    第一周总结
    课程总结
    周总结16
    河北省科技信息通用调查系统综合查询功能开发——Day9
  • 原文地址:https://www.cnblogs.com/herumw/p/9464486.html
Copyright © 2011-2022 走看看