bzoj 1901 有更新区间第k大 树状数组套可持久化线段树

来源:互联网 发布:49生男生女计算法准吗 编辑:程序博客网 时间:2024/04/30 16:01

http://www.lydsy.com/JudgeOnline/problem.php?id=1901

我的可持久化线段树消耗的内存太大了,在zoj超内存

如果对 上次的那题无修改的区间第k大的可持久化做法足够了解http://blog.csdn.net/haha593572013/article

那么稍微理解一下就能理解这道题了

在求区间第k大的时候,我们的本质其实是求出一棵包含且只包含所求区间信息的线段树,然后在整棵线段树中查询区间第k大的数,当然这棵线段树是通过做差得出来的,其实就是两个“前缀线段树”相减得出来的,即保存1~y区间信息的线段树 与  保存1~ x 区间信息的线段树节点信息相减,因为上题没有更新,所以每次直接从i-1时刻的线段树插入一个数得到i时刻的线段树,每次得到的新的线段树保存的信息都是1~ i 的信息,即都是前缀的信息

注意到了吗?前缀!!!那么如果有更新的操作的话,我们只需要维护好前缀的信息就可以了

具体做法是用树状数组来维护前缀(线段树)和,树状数组的每个节点又是一棵线段树,所以复杂度就要多乘一个log(n),即nlog^2(n)

求解x y区间第k大的数的时候还是一样,1到y的信息减去1到x-1的信息

具体的细节大家耐心研究下吧,蛮有意思的(树套树)

#include<cstdio>#include<algorithm>using namespace std;const int maxn = 120000;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1 int ls[maxn*20],rs[maxn*20],sum[maxn*20];int root[maxn],tot;  void build(int l,int r,int &rt){    rt=++tot;    sum[rt]=0;    if(l==r) return ;    int m=l+r>>1;    build(l,m,ls[rt]);    build(m+1,r,rs[rt]);}void update(int last,int p,int l,int r,int &rt,int v){    rt=++tot;    ls[rt]=ls[last]; rs[rt]=rs[last];sum[rt]=sum[last]+v;    if(l==r) return ;    int m=l+r>>1;    if(p <= m) update(ls[last],p,l,m,ls[rt],v);    else update(rs[last],p,m+1,r,rs[rt],v);}int cc,n,m;int num[maxn];char op[10010][3];const int NN = 10010;int san[NN*2],P[NN],Q[NN],K[NN];int L[30],R[30];int N,M;int query(int l,int r,int k){    if(l==r)     return l;    int m=l+r>>1;    int suma=0,sumb=0;    for(int i=1;i<=N;i++) suma+=sum[ls[L[i]]];    for(int i=1;i<=M;i++) sumb+=sum[ls[R[i]]];    int del=sumb-suma;    if(k <= del) {        for(int i=1;i<=N;i++) L[i]=ls[L[i]];        for(int i=1;i<=M;i++) R[i]=ls[R[i]];        return query(l,m,k);    }  else  {        for(int i=1;i<=N;i++) L[i]=rs[L[i]];        for(int i=1;i<=M;i++) R[i]=rs[R[i]];        return query(m+1,r,k-del);    }}int ask(int l,int r,int k){    N=0,M=0;    for(;l>0;l-=l&-l) L[++N]=root[l];    for(;r>0;r-=r&-r) R[++M]=root[r];    return query(1,cc,k);}void Bit_update(int x,int val,int flag){    for(;x<=n;x+=x&-x)     {        update(root[x],val,1,cc,root[x],flag);    }}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        san[++cc]=num[i];    }    for(int i=1;i<=m;i++)    {        scanf("%s%d%d",op[i],&P[i],&Q[i]);        if(op[i][0]=='Q'){  scanf("%d",&K[i]);  }        else    san[++cc]=Q[i];    }    sort(san+1,san+1+cc);    cc=unique(san+1,san+1+cc)-san-1;    for(int i=1;i<=n;i++) num[i]=lower_bound(san+1,san+1+cc,num[i])-san;    build(1,cc,root[0]);    for(int i=1;i<=n;i++)    Bit_update(i,num[i],1);    for(int i=1;i<=m;i++) {        if(op[i][0]=='Q'){            int id=ask(P[i]-1,Q[i],K[i]);            printf("%d\n",san[id]);        } else {            int pos=lower_bound(san+1,san+1+cc,Q[i]) - san;            Bit_update(P[i],num[P[i]],-1);            num[P[i]] = pos;            Bit_update(P[i],num[P[i]],1);        }    }    return 0;}


原创粉丝点击