【bzoj1901】dynamic ranking(带修改主席树/树套树)
题面地址(权限题)
首先说说怎么搞带修改主席树?
回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth。
那么我们如何支持修改操作?
考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下大概位置就好。
当然维护位置最好要离散化一下。我校某高傲的dalao直接写CTSC那道树上动态Kth,并且niubi地手写哈希维护。
别问我了在我写这篇文章的时候他还在debug呢。
由于我比较菜,只能先把这个区间的写了,并且我太菜只能lower_bound和unique……
代码学习的网上dalao以及hzwer。
1 #include<bits/stdc++.h> 2 #define N 10005 3 using namespace std; 4 inline int lowbit(int x){return x&-x;} 5 int n,m,sz,totn,totx,toty,a[N],b[N<<1],ca[N],cb[N],cc[N]; 6 int xx[N],yy[N],rt[N],size[600*N],ls[600*N],rs[600*N]; 7 void ins(int &o,int l,int r,int x,int q,int v){ 8 o=++sz;size[o]=size[x]+v;ls[o]=ls[x];rs[o]=rs[x]; 9 if(l==r)return;int mid=(l+r)>>1; 10 if(q<=mid)ins(ls[o],l,mid,ls[x],q,v); 11 else ins(rs[o],mid+1,r,rs[x],q,v); 12 } 13 int query(int l,int r,int q){ 14 if(l==r)return l; 15 int sum=0,mid=(l+r)>>1; 16 for(int i=1;i<=totx;i++)sum-=size[ls[xx[i]]]; 17 for(int i=1;i<=toty;i++)sum+=size[ls[yy[i]]]; 18 if(q<=sum){ 19 for(int i=1;i<=totx;i++)xx[i]=ls[xx[i]]; 20 for(int i=1;i<=toty;i++)yy[i]=ls[yy[i]]; 21 return query(l,mid,q); 22 } 23 else{ 24 for(int i=1;i<=totx;i++)xx[i]=rs[xx[i]]; 25 for(int i=1;i<=toty;i++)yy[i]=rs[yy[i]]; 26 return query(mid+1,r,q-sum); 27 } 28 } 29 void add(int x,int v){ 30 int k=lower_bound(b+1,b+totn+1,a[x])-b; 31 for(int i=x;i<=n;i+=lowbit(i))ins(rt[i],1,totn,rt[i],k,v); 32 } 33 inline int read(){ 34 int f=1,x=0;char ch; 35 do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); 36 do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); 37 return f*x; 38 } 39 int main(){char s[20]; 40 n=read();m=read(); 41 for(int i=1;i<=n;i++)a[i]=read(),b[++totn]=a[i]; 42 for(int i=1;i<=m;i++){ 43 scanf("%s",s);ca[i]=read();cb[i]=read(); 44 if(s[0]=='Q')cc[i]=read();else b[++totn]=cb[i]; 45 } 46 sort(b+1,b+totn+1); 47 totn=unique(b+1,b+totn+1)-b-1; 48 for(int i=1;i<=n;i++)add(i,1); 49 for(int i=1;i<=m;i++){ 50 if(cc[i]){ 51 totx=toty=0; 52 for(int j=ca[i]-1;j;j-=lowbit(j))xx[++totx]=rt[j]; 53 for(int j=cb[i];j;j-=lowbit(j))yy[++toty]=rt[j]; 54 printf("%d\n",b[query(1,totn,cc[i])]); 55 } 56 else{add(ca[i],-1);a[ca[i]]=cb[i];add(ca[i],1);} 57 } 58 }
啊当然树套树也是可以的啦。
1 #include<bits/stdc++.h> 2 #define N 200001 3 #define M 1300001 4 #define inf 1000000007 5 using namespace std; 6 int n,m,tmp,a[N>>1],rt[N],sz,size[M],ls[M],rs[M],val[M],w[M],rnd[M]; 7 inline void pushup(int x){ 8 //in Treap 9 size[x]=size[ls[x]]+size[rs[x]]+w[x]; 10 } 11 void rturn(int &k) 12 {int t=ls[k];ls[k]=rs[t];rs[t]=k;size[t]=size[k];pushup(k);k=t;} 13 void lturn(int &k) 14 {int t=rs[k];rs[k]=ls[t];ls[t]=k;size[t]=size[k];pushup(k);k=t;} 15 void ins(int &k,int x){// in Treap 16 if(!k){ 17 k=++sz;size[k]=1;w[k]=1;ls[k]=0;rs[k]=0;rnd[k]=rand();val[k]=x;return; 18 } 19 size[k]++;if(val[k]==x)w[k]++; 20 else if(x<val[k]){ins(ls[k],x);if(rnd[ls[k]]<rnd[k])rturn(k);} 21 else{ins(rs[k],x);if(rnd[rs[k]]<rnd[k])lturn(k);} 22 } 23 void del(int &k,int x){// in Treap 24 if(val[k]==x){ 25 if(w[k]>1){w[k]--;size[k]--;return;} 26 if(ls[k]*rs[k]==0)k=ls[k]+rs[k]; 27 else if(rnd[ls[k]]<rnd[rs[k]]){rturn(k);del(k,x);} 28 else{lturn(k);del(k,x);} 29 } 30 else if(x<val[k]){del(ls[k],x);size[k]--;} 31 else{del(rs[k],x);size[k]--;} 32 } 33 34 void change(int o,int l,int r,int q,int num,int v){ 35 // in Segment Tree 36 del(rt[o],v);ins(rt[o],num); 37 if(l==r)return; 38 int mid=(l+r)>>1; 39 if(q<=mid)change(o<<1,l,mid,q,num,v); 40 else change(o<<1|1,mid+1,r,q,num,v); 41 } 42 void build(int o,int l,int r,int q,int num){ 43 ins(rt[o],num);if(l==r)return; 44 int mid=(l+r)>>1; 45 if(q<=mid)build(o<<1,l,mid,q,num); 46 else build(o<<1|1,mid+1,r,q,num); 47 } 48 void find(int k,int x){ 49 if(!k)return; 50 if(val[k]<=x){tmp+=size[ls[k]]+w[k];find(rs[k],x);} 51 else find(ls[k],x); 52 } 53 void query(int o,int l,int r,int ql,int qr,int v){ 54 if(ql<=l&&r<=qr){find(rt[o],v);return;} 55 int mid=(l+r)>>1; 56 if(ql<=mid)query(o<<1,l,mid,ql,qr,v); 57 if(qr>mid)query(o<<1|1,mid+1,r,ql,qr,v); 58 } 59 inline int read(){ 60 int f=1,x=0;char ch; 61 do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); 62 do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); 63 return f*x; 64 } 65 char s[20]; 66 int main(){ 67 int T=read(); 68 while(T--){ 69 memset(rt,0,sizeof(rt));sz=0; 70 n=read();m=read(); 71 for(int i=1;i<=n;i++)a[i]=read(); 72 for(int i=1;i<=n;i++)build(1,1,n,i,a[i]); 73 for(int i=1;i<=m;i++){ 74 scanf("%s",s); 75 if(s[0]=='C'){ 76 int x=read(),y=read(); 77 change(1,1,n,x,y,a[x]); 78 a[x]=y; 79 } 80 else{ 81 int x=read(),y=read(),z=read(); 82 int l=0,r=inf; 83 while(l<=r){ 84 int mid=(l+r)>>1; 85 tmp=0;query(1,1,n,x,y,mid); 86 if(tmp>=z)r=mid-1;else l=mid+1; 87 } 88 printf("%d\n",l); 89 } 90 } 91 } 92 return 0; 93 }
其实这个树套树只要分清楚维护范围,也不是很难写的那种。
不过对于这种恶心的数据结构题,整体二分也是可以做到的。
这里是will大爷写的整体二分的题解。
zzq wc-ctsc-apio-NOI Au;yql精通多项式;zyz精通女装;由乃精通数据结构;孔老师是毒奶大师;我没有学上:我们都有光明的前途。