zoukankan      html  css  js  c++  java
  • ZOJ2112 Dynamic Rankings(树套树:树状数组套主席树)

    写法一:

    树状维护区间,内部主席树(动态开点)维护值域;

    树状数组的结点i代表第i个版本的权值线段树并且其是建立在原区间 [ i - lowbit(i) + 1 , i ] ;

    通过树状数组对结点(每个节点都是一个线段树)求和,就能得到一个完整版本的主席树;

    由于树状数组的特殊性,这种写法不需要保存历史版本,直接通过树状向上更新即可;

     但也正是这种写法不能保存历史版本,达不到树链的共用,在内存开销上比较大;

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<double,double> pdd;
    const int N=6e4+5;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    const double eps=1e-9;
    const long double pi=acos(-1.0L);
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define pb push_back
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    struct node{ int l,r,v; }c[N*40];
    int root[N],t[N],a[N],L[N],R[N],K[N],cmd[N],len,tot,n,m,cnt;
    int qx[N],qy[N],tx,ty;
    void update(int l,int r,int &now,int pos,int d)
    {
        if(now==0) now=++cnt;//没有保存历史版本,如果之前结点存在,也就没有必要再开一个新的节点了;
        c[now].v+=d;
        if(l==r) return ;
        int mid=l+r>>1;
        if(pos<=mid) update(l,mid,c[now].l,pos,d);
        else update(mid+1,r,c[now].r,pos,d);
    }
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    void add(int x,int y)
    {
        for(int i=x;i<=n;i+=lowbit(i)) update(1,len,root[i],a[x],y);
    }
    int query(int l,int r,int k)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        int sum=0;
        for(int i=1;i<=ty;i++) sum+=c[c[qy[i]].l].v;
        for(int i=1;i<=tx;i++) sum-=c[c[qx[i]].l].v;
        if(k<=sum)
        {
            for(int i=1;i<=ty;i++) qy[i]=c[qy[i]].l;
            for(int i=1;i<=tx;i++) qx[i]=c[qx[i]].l;
            return query(l,mid,k);
        }
        else
        {
            for(int i=1;i<=ty;i++) qy[i]=c[qy[i]].r;
            for(int i=1;i<=tx;i++) qx[i]=c[qx[i]].r;
            return query(mid+1,r,k-sum);
        }
    }
    int main()
    {
        int T=read();
        while(T--)
        {
            for(int i=1;i<=cnt;i++) root[i]=c[i].l=c[i].r=c[i].v=0;
            cnt=tx=ty=0;
            tot=n=read(),m=read();
            for(int i=1;i<=n;i++) t[i]=a[i]=read();
            for(int i=1;i<=m;i++)
            {
                char ch[2];
                int x,y,z;
                scanf("%s",ch);
                cmd[i]=ch[0];
                if(ch[0]=='Q') L[i]=read(),R[i]=read(),K[i]=read();
                else L[i]=read(),t[++tot]=R[i]=read();
            }
            sort(t+1,t+tot+1);
            len=unique(t+1,t+tot+1)-t-1;
            //for(int i=1;i<=len;i++) printf("%d%c",t[i],i==len?'
    ':' ');
            for(int i=1;i<=n;i++) a[i]=lower_bound(t+1,t+len+1,a[i])-t;
            for(int i=1;i<=n;i++) add(i,1);
            for(int i=1;i<=m;i++)
            {
                if(cmd[i]=='Q')
                {
                    tx=ty=0;
                    for(int j=L[i]-1;j;j-=lowbit(j)) qx[++tx]=root[j];
                    for(int j=R[i];j;j-=lowbit(j)) qy[++ty]=root[j];
                    printf("%d
    ",t[query(1,len,K[i])]);
                }
                else
                {
                    add(L[i],-1);
                    a[L[i]]=lower_bound(t+1,t+len+1,R[i])-t;
                    add(L[i],1);
                }
            }
        }
        return 0;
    }
    写法一

     写法二:

    在写法一的基础上进行改进:写法一的树状是维护原区间以及修改部分的主席树,(n+m)lognlogn 的内存量相当大,

    而第二种写法中,直接对原区间建立静态的主席树,而树状只维护主席树被修改的部分,原理同方法一,每次询问则同时查询静态主席树和树状的被修改部分,

    如此一来空间复杂度就能优化到 O(nlogn+mlognlogn) 了;

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<double,double> pdd;
    const int N=5e4+5;
    const int M=1e4+5;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    const double eps=1e-9;
    const long double pi=acos(-1.0L);
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define pb push_back
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    struct node{int l,r,s;}c[N*40];
    int root[N],rooc[N];//root 主席树的根,rooc 树状的根
    int tmp[N+M],a[N],cnt,len,tot,n,m;
    int qx[M],qy[M],tx,ty,L[M],R[M],K[M],cmd[N];
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int l,int r,int pre,int &now,int pos,int v)
    {
        now=++cnt,c[now]=c[pre],c[now].s+=v; //这里建立静态主席树,需要保存历史版本,如果想在树状上节约空间,可以加一个flag
        if(l==r) return ;
        int mid=l+r>>1;
        if(pos<=mid) update(l,mid,c[pre].l,c[now].l,pos,v);
        else update(mid+1,r,c[pre].r,c[now].r,pos,v);
    }
    void add(int x,int y)
    {
        int d=lower_bound(tmp+1,tmp+len+1,a[x])-tmp;
        for(int i=x;i<=n;i+=lowbit(i)) update(1,len,rooc[i],rooc[i],d,y);
    }
    int query(int l,int r,int x,int y,int k)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        int sum=c[c[y].l].s-c[c[x].l].s;
        for(int i=1;i<=tx;i++) sum-=c[c[qx[i]].l].s;
        for(int i=1;i<=ty;i++) sum+=c[c[qy[i]].l].s;
        if(k<=sum)
        {
            for(int i=1;i<=tx;i++) qx[i]=c[qx[i]].l;
            for(int i=1;i<=ty;i++) qy[i]=c[qy[i]].l;
            return query(l,mid,c[x].l,c[y].l,k);
        }
        else
        {
            for(int i=1;i<=tx;i++) qx[i]=c[qx[i]].r;
            for(int i=1;i<=ty;i++) qy[i]=c[qy[i]].r;
            return query(mid+1,r,c[x].r,c[y].r,k-sum);
        }
    }
    int main()
    {
        int T=read();
        while(T--)
        {
            tot=n=read(),m=read();
            for(int i=1;i<=n;i++) tmp[i]=a[i]=read();
            for(int i=1;i<=m;i++)
            {
                char ch[2];
                scanf("%s",ch);
                cmd[i]=ch[0]=='Q';
                if(cmd[i]==1) L[i]=read(),R[i]=read(),K[i]=read();
                else L[i]=read(),tmp[++tot]=R[i]=read();
            }
            sort(tmp+1,tmp+tot+1);
            len=unique(tmp+1,tmp+tot+1)-tmp-1;
            for(int i=1;i<=n;i++)
            {
                int x=lower_bound(tmp+1,tmp+len+1,a[i])-tmp;
                update(1,len,root[i-1],root[i],x,1);
                //printf("cnt = %d
    ",cnt);
            }
            for(int i=1;i<=m;i++)
            {
                if(cmd[i])
                {
                    tx=ty=0;
                    for(int j=L[i]-1;j;j-=lowbit(j)) qx[++tx]=rooc[j];
                    for(int j=R[i];j;j-=lowbit(j)) qy[++ty]=rooc[j];
                    printf("%d
    ",tmp[query(1,len,root[L[i]-1],root[R[i]],K[i])]);
                }
                else
                {
                    add(L[i],-1);
                    a[L[i]]=R[i];
                    add(L[i],1);
                }
    
            }
            for(int i=1;i<=cnt;i++) root[i]=rooc[i]=0,c[i]=c[0];
            cnt=0;
        }
        return 0;
    }
    写法二

    内存节约版update:(树状不保存历史版本,静态主席树保存历史版本)

    void update(int l,int r,int pre,int &now,int pos,int v,int flag)//flag=1,主席树;flag=0,树状数组
    {
        if(flag||!flag&&now==0) now=++cnt,c[now]=c[pre];
        c[now].s+=v;
        if(l==r) return ;
        int mid=l+r>>1;
        if(pos<=mid) update(l,mid,c[pre].l,c[now].l,pos,v,flag);
        else update(mid+1,r,c[pre].r,c[now].r,pos,v,flag);
    }
    View Code
  • 相关阅读:
    操作系统复习
    Google hack语法
    c++的set重载运算符
    华为笔试题
    Flume+Kafka整合
    kafka相关知识点总结
    kafka中生产者和消费者API
    Kafka集群环境搭建
    Storm消息容错机制(ack-fail机制)
    Storm通信机制(了解)
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12404840.html
Copyright © 2011-2022 走看看