BZOJ3196(TYVJ1730)二逼平衡树
传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3196
http://www.tyvj.cn/Problem_Show.aspx?id=1730
3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBDescription
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
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可能为负数
WRNM....这题我改了一上午。。题目挺水的。。但是要注意细节。。最大的细节就是k不在树里你怎么判断他的排名。。一定要模拟清楚了。。。
还要平衡树删除叶子节点的。。也要想清楚怎么删。。
Codes:
#include<set> #include<queue> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 50010; const int inf = 2147483647; #define Ch1 (i<<1) #define Ch2 (Ch1|1) #define L(i) (tre[i].s[0]) #define R(i) (tre[i].s[1]) #define For(i,n) for(int i=1;i<=n;i++) #define Rep(i,l,r) for(int i=l;i<=r;i++) struct tnode{ int l,r,mid; int rt; }T[N<<2]; struct treap{ int s[2],v,size,pri,p; void Sets(int x,int y,int z){ size = 1; v = x; pri = y;p = z; } }tre[N<<5]; int n,m,l,r,k,A[N],op,tot; void Update(int i){ tre[i].size = tre[L(i)].size + tre[R(i)].size + 1; } void Rot(int &y,int f){ int x = tre[y].s[!f]; tre[y].s[!f] = tre[x].s[f]; tre[x].s[f] = y; Update(y);Update(x); y = x; } void Insert(int &i,int v,int p){ if(!i){ tre[i=++tot].Sets(v,rand(),p); return; } int f = v > tre[i].v; Insert(tre[i].s[f],v,i); if(tre[tre[i].s[f]].pri > tre[i].pri) Rot(i,!f); else Update(i); } void Del(int &i,int v){ if(tre[i].v==v){ if(!L(i)||!R(i)){ if((!L(i))&&(!R(i))){ tre[i].size = 0; i = 0;return; } if(!tre[i].s[0]) i = tre[i].s[1]; else i = tre[i].s[0]; } else{ int f = tre[L(i)].pri > tre[R(i)].pri; Rot(i,f); Del(tre[i].s[f],v); } }else Del(tre[i].s[v>tre[i].v],v); Update(i); } void Build(int l,int r,int i){ T[i].l = l ;T[i].r = r;T[i].mid = (l+r)>>1; Rep(j,l,r) Insert(T[i].rt,A[j],T[i].rt); if(l==r) return; Build(l,T[i].mid,Ch1); Build(T[i].mid+1,r,Ch2); } void read(int &v){ char ch = getchar(); int num = 0 , q = 1; while(ch>'9'||ch<'0'){ if(ch=='-') q = -1; ch = getchar(); } while(ch>='0'&&ch<='9'){ num = num * 10 + ch - '0'; ch = getchar(); } v = num * q; } int ranks(int i,int v){ if(!i) return 0; if(tre[i].v >= v) return ranks(L(i),v); else return tre[L(i)].size + 1 + ranks(R(i),v); } int prev(int i,int v){ if(!i) return -inf; if(tre[i].v < v) return max(tre[i].v,prev(R(i),v)); else return prev(L(i),v); } int succ(int i,int v){ if(!i) return inf; if(tre[i].v> v) return min(tre[i].v,succ(L(i),v)); else return succ(R(i),v); } int query(int i,int l,int r,int v){ if(l<=T[i].l&&T[i].r<=r){ if(op==1||op==2) return ranks(T[i].rt,v); if(op==4) return prev(T[i].rt,v); if(op==5) return succ(T[i].rt,v); } if(r<=T[i].mid) return query(Ch1,l,r,v);else if(l>T[i].mid) return query(Ch2,l,r,v);else{ if(op==1||op==2) return query(Ch1,l,T[i].mid,v) + query(Ch2,T[i].mid+1,r,v); if(op==4) return max(query(Ch1,l,T[i].mid,v),query(Ch2,T[i].mid+1,r,v)); if(op==5) return min(query(Ch1,l,T[i].mid,v),query(Ch2,T[i].mid+1,r,v)); } } void Modify(int i,int x,int delta){ Del(T[i].rt,A[x]); Insert(T[i].rt,delta,i); if(T[i].l==T[i].r) { A[x] = delta; return; } if(x<=T[i].mid) Modify(Ch1,x,delta); else Modify(Ch2,x,delta); } int main(){ #ifndef ONLINE_JUDGE freopen("sb.in","r",stdin); freopen("sb.out","w",stdout); #endif //srand(time(NULL)); read(n);read(m); For(i,n) read(A[i]); Build(1,n,1); For(i,m){ read(op); if(op==3){read(l);read(r);Modify(1,l,r);continue;}; read(l);read(r);read(k); if(op==1) printf("%d\n",query(1,l,r,k)+1); if(op==2){ int Left = 0 , Right = inf; while(Right - Left > 1){ int Mid = (Left + Right) >> 1; if(query(1,l,r,Mid) >= k) Right = Mid; else Left = Mid; } if(query(1,l,r,Right)+1==k) printf("%d\n",Right); else printf("%d\n",Left); } if(op==4) printf("%d\n",query(1,l,r,k)); if(op==5) printf("%d\n",query(1,l,r,k)); } return 0; }