[BZOJ3196]二逼平衡树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3196]二逼平衡树相关的知识,希望对你有一定的参考价值。
人生第一次写树套树
这题是区间上的数值操作,所以我们用区间数据结构套数值数据结构
我选择了线段树套splay
其实就是对于线段树的每个节点$x$,若它代表的区间为$[l,r]$,则在这个线段树节点上建一棵含$A_{l\\cdots r}$的splay
对$1$操作:直接按线段树的方式把$[l,r]$分为一些区间,在每个区间内找比$k$小的数的个数,最后$+1$即可
对$2$操作:二分答案,将$1$操作作为二分条件
对$3$操作:按线段树单点修改的方式,每到一个线段树节点就在当前的splay上删除$A_pos$再插入$k$
对$4$操作:按线段树的方式分割区间,找每个区间内$k$的前驱,最后取最大值为答案
对$5$操作:按线段树的方式分割区间,找每个区间内$k$的后继,最后取最小值为答案
interesting
#include<stdio.h> int root[200010],a[50010],ch[1600010][2],fa[1600010],siz[1600010],v[1600010],tot,n,*rt; void rot(int x){ int y,z,B,f; y=fa[x]; z=fa[y]; if(y==*rt)*rt=x; f=(ch[y][0]==x); B=ch[x][f]; fa[x]=z; fa[y]=x; if(B)fa[B]=y; ch[x][f]=y; ch[y][f^1]=B; if(ch[z][0]==y)ch[z][0]=x; if(ch[z][1]==y)ch[z][1]=x; z=siz[x]; siz[x]=siz[y]; siz[y]-=(z-siz[B]); } void splay(int x){ int y,z; while(x!=*rt){ y=fa[x]; z=fa[y]; if(y==*rt) rot(x); else{ if((ch[y][0]==x&&ch[z][0]==y)||(ch[y][1]==x&&ch[z][1]==y)){ rot(y); rot(x); }else{ rot(x); rot(x); } } } } int _insert(int&x,int val){ if(x==0){ tot++; x=tot; v[x]=val; } siz[x]++; int k=x; if(val<v[x]){ k=_insert(ch[x][0],val); fa[ch[x][0]]=x; } if(val>v[x]){ k=_insert(ch[x][1],val); fa[ch[x][1]]=x; } return k; } void insert(int&x,int val){ splay(_insert(x,val)); } void build(int l,int r,int x){ rt=root+x; for(int i=l;i<=r;i++)insert(root[x],a[i]); if(l==r)return; int mid=(l+r)>>1; if(l<=mid)build(l,mid,x<<1); if(mid<r)build(mid+1,r,x<<1|1); } int max(int a,int b){return a>b?a:b;} int getrank(int x,int val){ if(x==0)return 0; if(val<v[x])return getrank(ch[x][0],val); if(val>v[x])return max(getrank(ch[x][1],val),0)+siz[x]-siz[ch[x][1]]; return siz[ch[x][0]]; } int getrank(int L,int R,int val,int l,int r,int x){ if(L<=l&&r<=R){ rt=root+x; return getrank(root[x],val); } int mid=(l+r)>>1,ans=0; if(L<=mid)ans+=getrank(L,R,val,l,mid,x<<1); if(mid<R)ans+=getrank(L,R,val,mid+1,r,x<<1|1); return ans; } int getkth(int l,int r,int k){ int L,R,mid,ans; L=-100000000; R=100000000; while(L<=R){ mid=(L+R)>>1; if(getrank(l,r,mid,1,n,1)+1<=k){ L=mid+1; ans=mid; }else R=mid-1; } return ans; } void merge(int a,int b){ if(a==0){ *rt=b; return; } *rt=a; if(b==0)return; while(ch[a][1])a=ch[a][1]; splay(a); ch[a][1]=b; siz[a]+=siz[b]; fa[b]=a; } void erase(int x,int val){ if(val==v[x]){ splay(x); if(siz[x]-siz[ch[x][0]]-siz[ch[x][1]]>1){ siz[x]--; return; } fa[ch[x][0]]=fa[ch[x][1]]=0; siz[x]=0; merge(ch[x][0],ch[x][1]); ch[x][0]=ch[x][1]=0; return; } if(val<v[x])erase(ch[x][0],val); if(val>v[x])erase(ch[x][1],val); } void modify(int pos,int val,int l,int r,int x){ rt=root+x; erase(root[x],a[pos]); insert(root[x],val); if(l==r)return; int mid=(l+r)>>1; if(pos<=mid) modify(pos,val,l,mid,x<<1); else modify(pos,val,mid+1,r,x<<1|1); } #define inf 1000000000 int presc(int x,int val){ int ans=-inf; while(x){ if(v[x]<val){ ans=v[x]; x=ch[x][1]; }else x=ch[x][0]; } return ans; } int presc(int L,int R,int val,int l,int r,int x){ if(L<=l&&r<=R)return presc(root[x],val); int ans=-inf,mid=(l+r)>>1; if(L<=mid)ans=max(ans,presc(L,R,val,l,mid,x<<1)); if(mid<R)ans=max(ans,presc(L,R,val,mid+1,r,x<<1|1)); return ans; } int nexsc(int x,int val){ int ans=inf; while(x){ if(v[x]>val){ ans=v[x]; x=ch[x][0]; }else x=ch[x][1]; } return ans; } int min(int a,int b){return a<b?a:b;} int nexsc(int L,int R,int val,int l,int r,int x){ if(L<=l&&r<=R)return nexsc(root[x],val); int ans=inf,mid=(l+r)>>1; if(L<=mid)ans=min(ans,nexsc(L,R,val,l,mid,x<<1)); if(mid<R)ans=min(ans,nexsc(L,R,val,mid+1,r,x<<1|1)); return ans; } int main(){ int m,i,op,l,r,k; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",a+i); build(1,n,1); while(m--){ scanf("%d%d%d",&op,&l,&r); if(op!=3)scanf("%d",&k); if(op==1)printf("%d\\n",getrank(l,r,k,1,n,1)+1); if(op==2)printf("%d\\n",getkth(l,r,k)); if(op==3){ modify(l,r,1,n,1); a[l]=r; } if(op==4)printf("%d\\n",presc(l,r,k,1,n,1)); if(op==5)printf("%d\\n",nexsc(l,r,k,1,n,1)); } }
以上是关于[BZOJ3196]二逼平衡树的主要内容,如果未能解决你的问题,请参考以下文章