bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
Output
对于操作1,2,4,5各输出一行,表示查询结果
Sample Input
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
Sample Output
2
4
3
4
9
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
线段树套平衡树
#include<cstdio> #include<algorithm> using namespace std; #define M 3000001 #define N 50001 int id=0; int siz[M],cnt[M],key[M]; int fa[M],ch[M][2]; struct TREE { int root,l,r; }tr[N<<2]; int data[N]; void Splay_up(int k) { siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+cnt[k]; } void rotate(int x,int &goal) { int y=fa[x],z=fa[y]; int l=ch[y][1]==x,r=l^1; if(y==goal) goal=x; else ch[z][ch[z][1]==y]=x; ch[y][l]=ch[x][r]; ch[x][r]=y; fa[x]=z; fa[y]=x; fa[ch[y][l]]=y; Splay_up(y); } void splay(int x,int &goal) { int y,z; while(x!=goal) { y=fa[x]; z=fa[y]; if(y!=goal) { if(ch[z][0]==y ^ ch[y][0]==x) rotate(x,goal); else rotate(y,goal); } rotate(x,goal); Splay_up(x); } } void Splay_insert(int &rt,int w) { if(!rt) { rt=++id; siz[rt]=cnt[rt]=1; key[rt]=w; return; } if(key[rt]==w) cnt[rt]++; else if(w<key[rt]) Splay_insert(ch[rt][0],w),fa[ch[rt][0]]=rt; else Splay_insert(ch[rt][1],w),fa[ch[rt][1]]=rt; Splay_up(rt); } int Splay_getpre(int rt,int x) { int now=rt,ret; while(now) { if(key[now]>=x) now=ch[now][0]; else ret=now,now=ch[now][1]; } return ret; } int Splay_getsuc(int rt,int x) { int now=rt,ret; while(now) { if(key[now]<=x) now=ch[now][1]; else ret=now,now=ch[now][0]; } return ret; } int Splay_number(int now,int w) { while(1) { if(key[now]==w) return now; if(w<key[now]) now=ch[now][0]; else now=ch[now][1]; } } void del(int & rt,int w) { int num=Splay_number(rt,w); splay(num,rt); if(cnt[num]>1) cnt[num]--, siz[num]--; else { int pre=Splay_getpre(rt,w); splay(pre,rt); ch[pre][1]=ch[num][1]; fa[ch[pre][1]]=pre; Splay_up(pre); } } void add_dummy(int rt,int w,int d) { ch[rt][d]=++id; siz[rt]++; fa[id]=rt; siz[id]=cnt[id]=1; key[id]=w; } void build(int k,int l,int r) { tr[k].l=l; tr[k].r=r; if(l==r) return; int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void Segment_insert(int k,int pos,int w) { Splay_insert(tr[k].root,w); if(tr[k].l==tr[k].r) return; int mid=tr[k].l+tr[k].r>>1; if(pos<=mid) Segment_insert(k<<1,pos,w); else Segment_insert(k<<1|1,pos,w); } void dummy(int k) { int pre=Splay_getsuc(tr[k].root,-1),suc=Splay_getpre(tr[k].root,1e8); splay(pre,tr[k].root); add_dummy(pre,-1e8-1,0); splay(suc,tr[k].root); add_dummy(suc,1e8+1,1); if(tr[k].l==tr[k].r) return; dummy(k<<1); dummy(k<<1|1); } int order(int k,int opl,int opr,int w) { if(tr[k].l>=opl && tr[k].r<=opr) { int pre=Splay_getpre(tr[k].root,w); splay(pre,tr[k].root); return siz[ch[pre][0]]+cnt[pre]-1; } int mid=tr[k].l+tr[k].r>>1,tmp=0; if(opl<=mid) tmp+=order(k<<1,opl,opr,w); if(opr>mid) tmp+=order(k<<1|1,opl,opr,w); return tmp; } int Segment_number(int l,int r,int w) { int ll=1,rr=1e8,mid,tmp,ans; while(ll<=rr) { mid=ll+rr>>1; tmp=order(1,l,r,mid); if(tmp<w) ans=mid,ll=mid+1; else rr=mid-1; } return ans; } void modify(int k,int pos,int before,int now) { del(tr[k].root,before); Splay_insert(tr[k].root,now); if(tr[k].l==tr[k].r) { data[tr[k].l]=now; return; } int mid=tr[k].l+tr[k].r>>1; if(pos<=mid) modify(k<<1,pos,before,now); else modify(k<<1|1,pos,before,now); } int Segment_getpre(int k,int l,int r,int w) { if(tr[k].l>=l && tr[k].r<=r) return key[Splay_getpre(tr[k].root,w)]; int mid=tr[k].l+tr[k].r>>1,tmp=-1e8-1; if(l<=mid) tmp=max(tmp,Segment_getpre(k<<1,l,r,w)); if(r>mid) tmp=max(tmp,Segment_getpre(k<<1|1,l,r,w)); return tmp; } int Segment_getsuc(int k,int l,int r,int w) { if(tr[k].l>=l && tr[k].r<=r) return key[Splay_getsuc(tr[k].root,w)]; int mid=tr[k].l+tr[k].r>>1,tmp=1e8+1; if(l<=mid) tmp=min(tmp,Segment_getsuc(k<<1,l,r,w)); if(r>mid) tmp=min(tmp,Segment_getsuc(k<<1|1,l,r,w)); return tmp; } int main() { freopen("psh.in","r",stdin); freopen("psh.out","w",stdout); int n,m; scanf("%d%d",&n,&m); build(1,1,n); for(int i=1;i<=n;i++) { scanf("%d",&data[i]); Segment_insert(1,i,data[i]); } dummy(1); int opt,l,r,k; while(m--) { scanf("%d",&opt); if(opt==1) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",order(1,l,r,k)+1); } else if(opt==2) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",Segment_number(l,r,k)); } else if(opt==3) { scanf("%d%d",&l,&k); modify(1,l,data[l],k); } else if(opt==4) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",Segment_getpre(1,l,r,k)); } else { scanf("%d%d%d",&l,&r,&k); printf("%d\n",Segment_getsuc(1,l,r,k)); } } }