【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大爷写的整体二分的题解。

posted @ 2017-05-09 21:48  zcysky  阅读(3028)  评论(2编辑  收藏  举报