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;
}

  

原文地址:https://www.cnblogs.com/kkrisen/p/3881365.html