zoukankan      html  css  js  c++  java
  • zoj 2112 主席树套树状数组

    现在把主席树的原理给弄清楚了,从i=1开始,每次新插入一个数,就为他建一棵线段树(当然第一次i=0的时候是建一棵空树),线段树里面保存的是1-i的树的位置情况

    简单来说,如果有m个树,则每棵线段树都是范围为1-m的,至于1-i没有m个那就先让它空着不管,我只负责1-i里面的数的位置情况插入到线段树里面,左孩子是大小k<=size/2的,右孩子是k>size的,size是线段树的深入层次而定,一开始就是m的,而不用每次都为1-i每个树插入值(不仅耗时,空间也耗不起),我只考虑当前这个Ai,至于1到i-1,已经在T[i-1]里面存了,我如果当前孩子是往左走的,那我复用T[i-1]的右孩子即可,反过来也是一样的,这样,每次建树 最多logN,最多也只建了logN个节点,所有总节点数目为N*logN,在N为不超过千万的范围内,是可以承受的。。。不过这道题为什么要*40才能过。。我也没搞清,好像觉得不用开这么大,但我试了下不开久会WA。

    因为主席树每颗线段树结构相同并且还高度复用,所以他的一个很奇妙的特性就是他支持加减操作,一般就是用他的减操作,要求区间A到B的,则用T[j] 和T[i-1]的左支相减即可得到当前这个区间里线段树左边存的是多大的,右边存的是多大的,用pos代进去即可,往左走 往右走,把整个二分走完即可得到答案

    树状数组套线段树我暂时还没完全弄清,反正为了记录修改,每次都像之前插入值一样新开了树,而且要用离线,把要修改的那些值预先存进去

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N =60000+10;
    const int maxn=N*40;
    int tot;
    int T[N],A[N],t[N],s[N];
    int lson[maxn],rson[maxn],c[maxn];
    int used[N];
    int n,q,m;
    struct node
    {
       int kind,l,r,k;
    }Q[10010];
    void init()
    {
        sort(t+1,t+1+m);
        m=unique(t+1,t+1+m)-t-1;
    }
    int build(int l,int r)
    {
        int rt=tot++;
        c[rt]=0;
        if (l>=r) return rt;
        int mid=(l+r)>>1;
        lson[rt]=build(l,mid);
        rson[rt]=build(mid+1,r);
        return rt;
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    int sum(int x)
    {
        int ret=0;
        while (x>0)
        {
            ret+=c[lson[used[x]]];
            x-=lowbit(x);
        }
        return ret;
    }
    int query(int L,int R,int k)
    {
        int lrt=T[L-1];
        int rrt=T[R];
        int l=1,r=m;
        for (int i=L-1;i;i-=lowbit(i)){
            used[i]=s[i];
        }
        for (int i=R;i;i-=lowbit(i)){
            used[i]=s[i];
        }
        while (l<r)
        {
            int mid=(l+r)>>1;
            int tmp=sum(R)-sum(L-1)+c[lson[rrt]]-c[lson[lrt]];
            if (tmp>=k){
                r=mid;
                for (int i=L-1;i;i-=lowbit(i)){
                    used[i]=lson[used[i]];
                }
                for (int i=R;i;i-=lowbit(i)){
                    used[i]=lson[used[i]];
                }
                lrt=lson[lrt];
                rrt=lson[rrt];
            }
            else{
                l=mid+1;
                k-=tmp;
                for (int i=L-1;i;i-=lowbit(i)){
                    used[i]=rson[used[i]];
                }
                for (int i=R;i;i-=lowbit(i)){
                    used[i]=rson[used[i]];
                }
                lrt=rson[lrt];
                rrt=rson[rrt];
            }
        }
        return l;
    }
    int inserts(int rt,int pos,int val)
    {
        int newrt=tot++,tmp=newrt;
        int l=1,r=m;
        c[newrt]=c[rt]+val;
        while (l<r)
        {
            int mid=(l+r)>>1;
            if (pos<=mid){
                lson[newrt]=tot++;
                rson[newrt]=rson[rt];
                rt=lson[rt];
                newrt=lson[newrt];
                r=mid;
            }
            else{
                rson[newrt]=tot++;
                lson[newrt]=lson[rt];
                rt=rson[rt];
                newrt=rson[newrt];
                l=mid+1;
            }
            c[newrt]=c[rt]+val;
        }
        return tmp;
    }
    void add(int loc,int p,int val)
    {
        while (loc<=n)
        {
            s[loc]=inserts(s[loc],p,val);
            loc+=lowbit(loc);
        }
    }
    int main()
    {
        char op[5];
        int kase,a,b,k;
        scanf("%d",&kase);
        while (kase--)
        {
            tot=0;
            scanf("%d%d",&n,&q);
            for (int i=1;i<=n;i++) scanf("%d",&A[i]),t[i]=A[i];
            m=n;
            for (int i=0;i<q;i++){
                scanf("%s",op);
                if (op[0]=='Q'){
                    scanf("%d%d%d",&a,&b,&k);
                    Q[i]=(node){0,a,b,k};
                }
                else{
                    scanf("%d%d",&a,&b);
                    Q[i]=(node){1,a,b,0};
                    t[++m]=b;
                }
            }
            init();
            T[0]=build(1,m);
    
            for (int i=1;i<=n;i++){
                int pos=lower_bound(t+1,t+m+1,A[i])-t;
                T[i]=inserts(T[i-1],pos,1);
            }
            for (int i=0;i<=n;i++) s[i]=T[0];
            for (int i=0;i<q;i++)
            {
                int a,b,k;
                if (Q[i].kind==0){
                    a=Q[i].l;b=Q[i].r;k=Q[i].k;
                    int ans=query(a,b,k);
                    printf("%d
    ",t[ans]);
                }
                else{
                    a=Q[i].l;
                    b=Q[i].r;
                    int pos;
                    pos=lower_bound(t+1,t+1+m,A[a])-t;
                    add(a,pos,-1);
                    pos=lower_bound(t+1,t+1+m,b)-t;
                    add(a,pos,1);
                    A[a]=b;
                }
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    CentOS6.4 安装nmon
    CentOS6.4 访问域局网中Windows的共享
    将类似 12.56MB 36.89KB 转成 以K为单位的数字【备忘】
    ICE中间件相关
    HDFS介绍
    漫画描述HDFS工作原理
    离线安装Cloudera Manager 5和CDH5
    storm集群相关资料
    kafka相关资料
    jstatd
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3881365.html
Copyright © 2011-2022 走看看