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