BZOJ1901 - Dynamic Rankings(树状数组套主席树)
题目大意
给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下:
Q l r k 要求你查询区间[l,r]第k小的数是哪个
C i t 要求你把第i个数修改为t
题解
动态的区间第k小,如果还是按照静态的主席树做的话,每次修改需要对n个线段树进行修改,这样显然会TLE,所以我们需要用树状数组,这样每次只需要对logn颗线段树修改即可,修改的时间复杂度为logn^2,询问的时间复杂度为logn^2,空间复杂度为nlogn^2
还有一种空间复杂度为nlogn+mlogn^2的方法,就是先建立n颗静态的主席树,空间复杂度为nlogn,然后再更新的时候用树状数组套线段树,这样空间复杂度为mlogn^2,所以总空间复杂度为nlogn+mlogn^2
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAXN 140000 #define NN 10005 #define lson l,m,ls[s] #define rson m+1,r,rs[s] int ls[20*MAXN],rs[20*MAXN],cnt[20*MAXN]; int T[MAXN],tot; int len,n,m; int num[MAXN]; char op[10010][3]; int a[NN*2],lt[NN],rt[NN],K[NN]; int L[30],R[30]; int N,M; void build(int l,int r,int &s) { s=++tot; cnt[s]=0; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int last,int p,int l,int r,int &s,int d) { s=++tot; ls[s]=ls[last],rs[s]=rs[last],cnt[s]=cnt[last]+d; if(l==r) return; int m=(l+r)>>1; if(p<=m) update(ls[last],p,lson,d); else update(rs[last],p,rson,d); } int query(int l,int r,int k) { if(l==r) return r; int suma=0,sumb=0; for(int i=1; i<=N; i++) suma+=cnt[ls[L[i]]]; for(int i=1; i<=M; i++) sumb+=cnt[ls[R[i]]]; int m=(l+r)>>1,sum=sumb-suma; if(sum>=k) { 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-sum); } } int lowbit(int x) { return x&-x; } void BIT(int x,int value,int d) { while(x<=n) { update(T[x],value,1,len,T[x],d); x+=lowbit(x); } } int BIT_query(int l,int r,int k) { N=0,M=0; while(l>0) { L[++N]=T[l]; l-=lowbit(l); } while(r>0) { R[++M]=T[r]; r-=lowbit(r); } return query(1,len,k); } int main() { scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&num[i]); a[++len]=num[i]; } for(int i=1; i<=m; i++) { scanf("%s%d%d",op[i],<[i],&rt[i]); if(op[i][0]=='Q') scanf("%d",&K[i]); else a[++len]=rt[i]; } sort(a+1,a+len+1); len=unique(a+1,a+len+1)-a-1; for(int i=1; i<=n; i++) num[i]=lower_bound(a+1,a+1+len,num[i])-a; build(1,len,T[0]); for(int i=1; i<=n; i++) BIT(i,num[i],1); for(int i=1; i<=m; i++) if(op[i][0]=='Q') printf("%d\n",a[BIT_query(lt[i]-1,rt[i],K[i])]); else { BIT(lt[i],num[lt[i]],-1); int pos=lower_bound(a+1,a+len+1,rt[i])-a; num[lt[i]]=pos; BIT(lt[i],pos,1); } return 0; }