P2617 Dynamic Ranking(树状数组套主席树模板)

hhz6830975

2017-12-25 19:22:56

Personal

我是看这个学会的:https://www.cnblogs.com/Empress/p/4659824.html 树状数组套主席树可以实现带修改的主席树 树状数组每个元素内含一颗权值线段树,初始化逐个动态加点,修改同理,空间复杂度 O(nlognlogn) ~~然而我并不知道这和主席树有什么关系~~ ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=10010; int n,m,a[maxn]; int hash[maxn*2],hashN; inline int read(){ int ret=0,sign=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') sign=-1; else if(ch=='Q'||ch=='C') return ch; ch=getchar(); } while(ch>='0'&&ch<='9') {ret=ret*10+ch-'0'; ch=getchar();} return ret*sign; } struct Cmd{ char op; int x,y,z; }cmd[maxn]; struct node{ int val,l,r,son[2]; node(){} node(int _l,int _r){l=_l,r=_r,val=son[0]=son[1]=0;} }T[maxn*400]; int root[maxn],cnt; void ins(int op,int &u,int l,int r,int x){ if(!u) u=++cnt,T[u]=node(l,r); T[u].val+=op; int mid=(T[u].l+T[u].r)>>1; if(l==r) return; if(x<=mid) ins(op,T[u].son[0],l,mid,x); else ins(op,T[u].son[1],mid+1,r,x); } inline int lbt(int x){return x&(-x);} void add(int op,int u,int x){while(u<=n) ins(op,root[u],1,hashN,x),u+=lbt(u);} int tmpP[2][20],rtN[2]; int query(int l,int r,int k){ rtN[0]=rtN[1]=0; for(int i=l-1;i;i-=lbt(i)) tmpP[0][++rtN[0]]=root[i]; for(int i=r;i;i-=lbt(i)) tmpP[1][++rtN[1]]=root[i]; int vl=1,vr=hashN; while(vl!=vr){ int mid=(vl+vr)>>1,lsum[2]={0},rela; for(int i=0;i<=1;i++) for(int j=1;j<=rtN[i];j++) lsum[i]+=T[T[tmpP[i][j]].son[0]].val; rela=k>lsum[1]-lsum[0]; if(rela) k-=lsum[1]-lsum[0],vl=mid+1; else vr=mid; for(int i=0;i<=1;i++) for(int j=1;j<=rtN[i];j++) tmpP[i][j]=T[tmpP[i][j]].son[rela]; } return vl; } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) hash[i]=a[i]=read(); hashN=n; for(int i=1;i<=m;i++){ cmd[i].op=read(); if(cmd[i].op=='Q') cmd[i].x=read(),cmd[i].y=read(),cmd[i].z=read(); else cmd[i].x=read(),hash[++hashN]=cmd[i].y=read(); } sort(hash+1,hash+hashN+1); hashN=unique(hash+1,hash+hashN+1)-hash-1; for(int i=1;i<=n;i++){ a[i]=lower_bound(hash+1,hash+hashN+1,a[i])-hash; add(1,i,a[i]); } for(int i=1;i<=m;i++){ if(cmd[i].op=='Q') printf("%d\n",hash[query(cmd[i].x,cmd[i].y,cmd[i].z)]); else cmd[i].y=lower_bound(hash+1,hash+hashN+1,cmd[i].y)-hash,add(-1,cmd[i].x,a[cmd[i].x]),add(1,cmd[i].x,cmd[i].y),a[cmd[i].x]=cmd[i].y; } return 0; } ``` 这个空间复杂度是可以优化的 用静态主席树维护原序列,空间复杂度 O(nlogn) 树状数组保存修改部分,树状数组每个元素内含一颗权值线段树,需要修改时动态加点,空间复杂度 O(mlognlogn) 查询时tmp1存当前到原树的结点,tmp2预处理出树状数组要修改的logn个结点,两部分加起来就是实际值 总空间复杂度 O(nlogn+mlognlogn) ,当m较小时效果明显 ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=10010; int n,m,a[maxn]; int hash[maxn*2],hashN; inline int read(){ int ret=0,sign=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') sign=-1; if(ch=='Q'||ch=='C') return ch; ch=getchar(); } while(ch>='0'&&ch<='9') {ret=ret*10+ch-'0'; ch=getchar();} return ret*sign; } struct Cmd{ char op; int x,y,z; }cmd[maxn]; struct node{ int val,son[2]; }T1[maxn*20],T2[maxn*400]; int root1[maxn],root2[maxn],cnt1,cnt2; void build(int &u,int l,int r){ u=++cnt1; if(l==r) return; int mid=(l+r)>>1; build(T1[u].son[0],l,mid); build(T1[u].son[1],mid+1,r); } void ins1(int &u,int v,int l,int r,int x){ u=++cnt1,T1[u]=T1[v],++T1[u].val; int mid=(l+r)>>1; if(l==r) return; if(x<=mid) ins1(T1[u].son[0],T1[v].son[0],l,mid,x); else ins1(T1[u].son[1],T1[v].son[1],mid+1,r,x); } void ins2(int &u,int l,int r,int x,int op){ if(!u) u=++cnt2; T2[u].val+=op; int mid=(l+r)>>1; if(l==r) return; if(x<=mid) ins2(T2[u].son[0],l,mid,x,op); else ins2(T2[u].son[1],mid+1,r,x,op); } inline int lbt(int x){return x&-x;} inline void add(int u,int x,int op){while(u<=n) ins2(root2[u],1,hashN,x,op),u+=lbt(u);} int tmp1[2],tmp2[2][20],tmpN[2]; int query(int l,int r,int k){ tmpN[0]=tmpN[1]=0; tmp1[0]=root1[l-1],tmp1[1]=root1[r]; for(int i=l-1;i;i-=lbt(i)) tmp2[0][++tmpN[0]]=root2[i]; for(int i=r;i;i-=lbt(i)) tmp2[1][++tmpN[1]]=root2[i]; int vl=1,vr=hashN; while(vl!=vr){ int lsum=T1[T1[tmp1[1]].son[0]].val-T1[T1[tmp1[0]].son[0]].val; for(int i=1;i<=tmpN[0];i++) lsum-=T2[T2[tmp2[0][i]].son[0]].val; for(int i=1;i<=tmpN[1];i++) lsum+=T2[T2[tmp2[1][i]].son[0]].val; int rela=k>lsum; if(rela) k-=lsum,vl=((vl+vr)>>1)+1; else vr=(vl+vr)>>1; tmp1[0]=T1[tmp1[0]].son[rela],tmp1[1]=T1[tmp1[1]].son[rela]; for(int i=1;i<=tmpN[0];i++) tmp2[0][i]=T2[tmp2[0][i]].son[rela]; for(int i=1;i<=tmpN[1];i++) tmp2[1][i]=T2[tmp2[1][i]].son[rela]; //cout<<vl<<' '<<vr<<endl; } return vl; } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) hash[i]=a[i]=read(); hashN=n; for(int i=1;i<=m;i++){ cmd[i].op=read(); if(cmd[i].op=='Q') cmd[i].x=read(),cmd[i].y=read(),cmd[i].z=read(); else cmd[i].x=read(),hash[++hashN]=cmd[i].y=read(); } sort(hash+1,hash+hashN+1); hashN=unique(hash+1,hash+hashN+1)-hash-1; build(root1[0],1,hashN); for(int i=1;i<=n;i++){ a[i]=lower_bound(hash+1,hash+hashN+1,a[i])-hash; ins1(root1[i],root1[i-1],1,hashN,a[i]); } for(int i=1;i<=m;i++){ if(cmd[i].op=='Q') printf("%d\n",hash[query(cmd[i].x,cmd[i].y,cmd[i].z)]); else{ cmd[i].y=lower_bound(hash+1,hash+hashN+1,cmd[i].y)-hash; add(cmd[i].x,a[cmd[i].x],-1),add(cmd[i].x,cmd[i].y,1); a[cmd[i].x]=cmd[i].y; } } return 0; } ```