【bzoj1901】dynamic ranking(带修改主席树/树套树)

时间:2021-02-26 01:03:24

题面地址(权限题)

不用权限题的地址

首先说说怎么搞带修改主席树?

回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth。

那么我们如何支持修改操作?

考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下大概位置就好。

当然维护位置最好要离散化一下。我校某高傲的dalao直接写CTSC那道树上动态Kth,并且niubi地手写哈希维护。

【bzoj1901】dynamic ranking(带修改主席树/树套树)

别问我了在我写这篇文章的时候他还在debug呢。

由于我比较菜,只能先把这个区间的写了,并且我太菜只能lower_bound和unique……

代码学习的网上dalao以及hzwer。

 #include<bits/stdc++.h>
#define N 10005
using namespace std;
inline int lowbit(int x){return x&-x;}
int n,m,sz,totn,totx,toty,a[N],b[N<<],ca[N],cb[N],cc[N];
int xx[N],yy[N],rt[N],size[*N],ls[*N],rs[*N];
void ins(int &o,int l,int r,int x,int q,int v){
o=++sz;size[o]=size[x]+v;ls[o]=ls[x];rs[o]=rs[x];
if(l==r)return;int mid=(l+r)>>;
if(q<=mid)ins(ls[o],l,mid,ls[x],q,v);
else ins(rs[o],mid+,r,rs[x],q,v);
}
int query(int l,int r,int q){
if(l==r)return l;
int sum=,mid=(l+r)>>;
for(int i=;i<=totx;i++)sum-=size[ls[xx[i]]];
for(int i=;i<=toty;i++)sum+=size[ls[yy[i]]];
if(q<=sum){
for(int i=;i<=totx;i++)xx[i]=ls[xx[i]];
for(int i=;i<=toty;i++)yy[i]=ls[yy[i]];
return query(l,mid,q);
}
else{
for(int i=;i<=totx;i++)xx[i]=rs[xx[i]];
for(int i=;i<=toty;i++)yy[i]=rs[yy[i]];
return query(mid+,r,q-sum);
}
}
void add(int x,int v){
int k=lower_bound(b+,b+totn+,a[x])-b;
for(int i=x;i<=n;i+=lowbit(i))ins(rt[i],,totn,rt[i],k,v);
}
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){char s[];
n=read();m=read();
for(int i=;i<=n;i++)a[i]=read(),b[++totn]=a[i];
for(int i=;i<=m;i++){
scanf("%s",s);ca[i]=read();cb[i]=read();
if(s[]=='Q')cc[i]=read();else b[++totn]=cb[i];
}
sort(b+,b+totn+);
totn=unique(b+,b+totn+)-b-;
for(int i=;i<=n;i++)add(i,);
for(int i=;i<=m;i++){
if(cc[i]){
totx=toty=;
for(int j=ca[i]-;j;j-=lowbit(j))xx[++totx]=rt[j];
for(int j=cb[i];j;j-=lowbit(j))yy[++toty]=rt[j];
printf("%d\n",b[query(,totn,cc[i])]);
}
else{add(ca[i],-);a[ca[i]]=cb[i];add(ca[i],);}
}
}

啊当然树套树也是可以的啦。

 #include<bits/stdc++.h>
#define N 200001
#define M 1300001
#define inf 1000000007
using namespace std;
int n,m,tmp,a[N>>],rt[N],sz,size[M],ls[M],rs[M],val[M],w[M],rnd[M];
inline void pushup(int x){
//in Treap
size[x]=size[ls[x]]+size[rs[x]]+w[x];
}
void rturn(int &k)
{int t=ls[k];ls[k]=rs[t];rs[t]=k;size[t]=size[k];pushup(k);k=t;}
void lturn(int &k)
{int t=rs[k];rs[k]=ls[t];ls[t]=k;size[t]=size[k];pushup(k);k=t;}
void ins(int &k,int x){// in Treap
if(!k){
k=++sz;size[k]=;w[k]=;ls[k]=;rs[k]=;rnd[k]=rand();val[k]=x;return;
}
size[k]++;if(val[k]==x)w[k]++;
else if(x<val[k]){ins(ls[k],x);if(rnd[ls[k]]<rnd[k])rturn(k);}
else{ins(rs[k],x);if(rnd[rs[k]]<rnd[k])lturn(k);}
}
void del(int &k,int x){// in Treap
if(val[k]==x){
if(w[k]>){w[k]--;size[k]--;return;}
if(ls[k]*rs[k]==)k=ls[k]+rs[k];
else if(rnd[ls[k]]<rnd[rs[k]]){rturn(k);del(k,x);}
else{lturn(k);del(k,x);}
}
else if(x<val[k]){del(ls[k],x);size[k]--;}
else{del(rs[k],x);size[k]--;}
} void change(int o,int l,int r,int q,int num,int v){
// in Segment Tree
del(rt[o],v);ins(rt[o],num);
if(l==r)return;
int mid=(l+r)>>;
if(q<=mid)change(o<<,l,mid,q,num,v);
else change(o<<|,mid+,r,q,num,v);
}
void build(int o,int l,int r,int q,int num){
ins(rt[o],num);if(l==r)return;
int mid=(l+r)>>;
if(q<=mid)build(o<<,l,mid,q,num);
else build(o<<|,mid+,r,q,num);
}
void find(int k,int x){
if(!k)return;
if(val[k]<=x){tmp+=size[ls[k]]+w[k];find(rs[k],x);}
else find(ls[k],x);
}
void query(int o,int l,int r,int ql,int qr,int v){
if(ql<=l&&r<=qr){find(rt[o],v);return;}
int mid=(l+r)>>;
if(ql<=mid)query(o<<,l,mid,ql,qr,v);
if(qr>mid)query(o<<|,mid+,r,ql,qr,v);
}
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
char s[];
int main(){
int T=read();
while(T--){
memset(rt,,sizeof(rt));sz=;
n=read();m=read();
for(int i=;i<=n;i++)a[i]=read();
for(int i=;i<=n;i++)build(,,n,i,a[i]);
for(int i=;i<=m;i++){
scanf("%s",s);
if(s[]=='C'){
int x=read(),y=read();
change(,,n,x,y,a[x]);
a[x]=y;
}
else{
int x=read(),y=read(),z=read();
int l=,r=inf;
while(l<=r){
int mid=(l+r)>>;
tmp=;query(,,n,x,y,mid);
if(tmp>=z)r=mid-;else l=mid+;
}
printf("%d\n",l);
}
}
}
return ;
}

其实这个树套树只要分清楚维护范围,也不是很难写的那种。

不过对于这种恶心的数据结构题,整体二分也是可以做到的。

这里是will大爷写的整体二分的题解。

【bzoj1901】dynamic ranking(带修改主席树/树套树)