[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)
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
Sample Output
2 4 3 4 9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
Solution
#include <stdio.h> #include <stdlib.h> #define N 50010 #define inf 0x7fffffff #define opp 0x80000000 #define mid ((x>>1)+(y>>1)+(x&y&1)) #define dmax(x,y) ((x)>(y)?(x):(y)) #define dmin(x,y) ((x)<(y)?(x):(y)) #define RG register #define inline __inline__ __attribute__((always_inline)) inline int Rin(){ RG int x=0,c=getchar(),f=1; for(;c<48||c>57;c=getchar()) if(!(c^45))f=-1; for(;c>47&&c<58;c=getchar()) x=(x<<1)+(x<<3)+c-48; return x*f; } int n,m,a[N]; namespace Seg{ struct Treap{ struct Nt{ Nt*ch[2]; int s,w,v,r; Nt(RG int v,RG Nt*_) : v(v),r(rand()) { s=w=1; ch[0]=ch[1]=_; } inline void maintain(){ s=w+ch[0]->s+ch[1]->s; } }*root,*null; Treap(){ null=new Nt(0,0x0); null->s=null->w=0; null->r=inf; null->ch[0]=null->ch[1]=null; root=null; } void rotate(RG Nt*&o,RG int d){ Nt*k=o->ch[1^d]; o->ch[1^d]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void insert(RG Nt*&o,RG int v){ if(o==null){ o=new Nt(v,null); return; } o->s++; if(v==o->v) o->w++; else{ RG int d=v > o->v; insert(o->ch[d],v); if(o->ch[d]->r < o->r) rotate(o,1^d); } } void remove(RG Nt*&o,RG int v){ if(o==null) return; if(o->v==v){ if(o->w>1){ o->s--; o->w--; return; } if(o->ch[0]!=null && o->ch[1]!=null){ RG int d=o->ch[0]->r > o->ch[1]->r; rotate(o,d); remove(o->ch[d],v); } else o=o->ch[o->ch[0]==null]; } else{ o->s--; remove(o->ch[o->v < v],v); } if(o!=null) o->maintain(); } inline int pre(RG int v){ RG int ans=opp; for(RG Nt*o=root;o!=null;) v > o->v ? (ans=dmax(ans,o->v),o=o->ch[1]) : o=o->ch[0]; return ans; } inline int nxt(RG int v){ RG int ans=inf; for(RG Nt*o=root;o!=null;) v < o->v ? (ans=dmin(ans,o->v),o=o->ch[0]) : o=o->ch[1]; return ans; } inline int rank(RG int v){ RG int ans=0; for(Nt*o=root;o!=null;){ RG int d= v==o->v? -1 : (o->v < v); if(d==-1){ ans+=o->ch[0]->s; break; } d?(ans+=o->ch[0]->s+o->w,o=o->ch[1]):o=o->ch[0]; } return ans; } }rt[N<<2]; void build(RG int x,RG int y,RG int k){ for(RG int i=x;i<=y;i++) rt[k].insert(rt[k].root,a[i]); if(x<y){ build(x,mid,k<<1); build(mid+1,y,k<<1|1); } } void modify(RG int x,RG int y,RG int k,RG int pos,RG int num){ rt[k].remove(rt[k].root,a[pos]); rt[k].insert(rt[k].root,num); if(x<y) pos<=mid ? modify(x,mid,k<<1,pos,num): modify(mid+1,y,k<<1|1,pos,num); } int getrank(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){ if(x==l && y==r) return rt[k].rank(num); if(r<=mid) return getrank(x,mid,k<<1,l,r,num); if(l>mid) return getrank(mid+1,y,k<<1|1,l,r,num); return getrank(x,mid,k<<1,l,mid,num)+getrank(mid+1,y,k<<1|1,mid+1,r,num); } int getpre(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){ if(x==l && y==r) return rt[k].pre(num); if(r<=mid) return getpre(x,mid,k<<1,l,r,num); if(l>mid) return getpre(mid+1,y,k<<1|1,l,r,num); return dmax(getpre(x,mid,k<<1,l,mid,num),getpre(mid+1,y,k<<1|1,mid+1,r,num)); } int getnxt(RG int x,RG int y,RG int k,RG int l,RG int r,RG int num){ if(x==l && y==r) return rt[k].nxt(num); if(r<=mid) return getnxt(x,mid,k<<1,l,r,num); if(l>mid) return getnxt(mid+1,y,k<<1|1,l,r,num); return dmin(getnxt(x,mid,k<<1,l,mid,num),getnxt(mid+1,y,k<<1|1,mid+1,r,num)); } inline int getkth(RG int l,RG int r,RG int k){ RG int x=0,y=1e8; while(x<=y) getrank(1,n,1,l,r,mid) < k ? x=mid+1: y=mid-1; if(getrank(1,n,1,l,r,x)>=k) x=getpre(1,n,1,l,r,x); return x; } } int main(){ srand('K'+'a'+'i'+'b'+'a'); n=Rin(),m=Rin(); for(int i=1;i<=n;i++) a[i]=Rin(); Seg::build(1,n,1); while(m--){ RG int x,y,k,c=Rin(); switch(c){ case 1 : x=Rin(),y=Rin(),k=Rin(); printf("%d\n",Seg::getrank(1,n,1,x,y,k)+1); break; case 2 : x=Rin(),y=Rin(),k=Rin(); printf("%d\n",Seg::getkth(x,y,k)); break; case 3 : x=Rin(),k=Rin(); Seg::modify(1,n,1,x,k); a[x]=k; break; case 4 : x=Rin(),y=Rin(),k=Rin(); printf("%d\n",Seg::getpre(1,n,1,x,y,k)); break; case 5 : x=Rin(),y=Rin(),k=Rin(); printf("%d\n",Seg::getnxt(1,n,1,x,y,k)); break; default : break; } } return 0; }