BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=3196
可以处理区间问题的平衡树.
3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2412 Solved: 986
[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
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
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
Source
分析
树套树.可以用线段树套Treap.人生第一道树套树的题...
op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1.
op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre.
op3:先删后加.
op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有些区间可能找不到前驱/后驱,这时pre返回-INF,suc取INF.
p.s.
1.神一样的调了一下午....上午做完普通平衡树感觉自己好不熟练啊居然搞了一上午,中午敲完这个题以为能A,结果RE,之后就没救了...发现时remove函数的问题,也没找到问题在哪,在开始怀疑人生之前换回了白书上的写法,果然A了,再看看原来的写法也没什么错啊.于是重新写了一遍原来的方法,结果A了.然后开始找不同,后来发现是结构体里定义的小于号不知咋地不好使了...C++学得太渣,最后只好舍弃,改为手动判断大小了...也不知道问题出在哪,最后还是没有解决,好遗憾...
1.白书上的remove写法
1 #include <cstdio> 2 #include <cstdlib> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn=50000+5,oo=~0u>>1; 7 int n,q; 8 int a[maxn]; 9 struct Treap{ 10 struct node{ 11 node* ch[2]; 12 int v,r,s,c; 13 node(int v,node* t):v(v){ ch[0]=ch[1]=t; r=rand(); s=c=1; } 14 bool operator < (const node &rhs) const{ return r<rhs.r; } 15 void push_up() { s=ch[0]->s+ch[1]->s+c; } 16 }*root,*null; 17 Treap(){ 18 null=new node(0,NULL); 19 null->c=null->s=0; null->r=oo; 20 root=null; 21 } 22 void rotate(node* &o,bool d){ 23 node* k=o->ch[!d]; o->ch[!d]=k->ch[d]; k->ch[d]=o; 24 o->push_up(); k->push_up(); o=k; 25 } 26 void insert(node* &o,int x){ 27 if(o==null) o=new node(x,null); 28 else{ 29 if(x==o->v){ o->s++; o->c++; } 30 else{ 31 bool d=x>o->v; 32 insert(o->ch[d],x); 33 if(o->ch[d]<o) rotate(o,!d); 34 o->push_up(); 35 } 36 } 37 } 38 void remove(node* &o,int x){ 39 if(o->v==x){ 40 if(o->c>1) { o->c--; o->s--; } 41 else{ 42 if(o->ch[0]!=null&&o->ch[1]!=null){ 43 bool d=o->ch[0]<o->ch[1]; 44 rotate(o,d); remove(o->ch[d],x); o->push_up(); 45 } 46 else{ 47 node* u=o; 48 if(o->ch[0]==null) o=o->ch[1]; else o=o->ch[0]; 49 delete u; 50 } 51 } 52 } 53 else{ 54 bool d=x>o->v; 55 remove(o->ch[d],x); 56 o->push_up(); 57 } 58 } 59 int rank(int x){ 60 int ret=0,s; 61 for(node *t=root;t!=null;){ 62 s=t->ch[0]->s+t->c; 63 if(x>t->v) ret+=s,t=t->ch[1]; 64 else t=t->ch[0]; 65 } 66 return ret; 67 } 68 int pre(int x){ 69 int ret=-oo; 70 for(node* t=root;t!=null;){ 71 if(t->v<x) ret=t->v,t=t->ch[1]; 72 else t=t->ch[0]; 73 } 74 return ret; 75 } 76 int suc(int x){ 77 int ret=oo; 78 for(node* t=root;t!=null;){ 79 if(t->v>x) ret=t->v,t=t->ch[0]; 80 else t=t->ch[1]; 81 } 82 return ret; 83 } 84 }; 85 86 struct Segment_Tree{ 87 Treap tree[maxn*3]; 88 void build_tree(int l,int r,int k){ 89 for(int i=l;i<=r;i++) tree[k].insert(tree[k].root,a[i]); 90 if(l==r) return; 91 int mid=l+((r-l)>>1); 92 build_tree(l,mid,k<<1); build_tree(mid+1,r,k<<1|1); 93 } 94 int get_rank(int l,int r,int k,int x,int y,int X){ 95 if(l==x&&r==y) return tree[k].rank(X); 96 int mid=l+((r-l)>>1); 97 if(y<=mid) return get_rank(l,mid,k<<1,x,y,X); 98 else if(x>mid) return get_rank(mid+1,r,k<<1|1,x,y,X); 99 else return get_rank(l,mid,k<<1,x,mid,X)+get_rank(mid+1,r,k<<1|1,mid+1,y,X); 100 } 101 void change(int l,int r,int k,int id,int x){ 102 tree[k].remove(tree[k].root,a[id]); 103 tree[k].insert(tree[k].root,x); 104 if(l==r) return; 105 int mid=l+((r-l)>>1); 106 if(id<=mid) change(l,mid,k<<1,id,x); 107 else change(mid+1,r,k<<1|1,id,x); 108 } 109 int get_pre(int l,int r,int k,int x,int y,int X){ 110 if(l==x&&r==y) return tree[k].pre(X); 111 int mid=l+((r-l)>>1); 112 if(y<=mid) return get_pre(l,mid,k<<1,x,y,X); 113 else if(x>mid) return get_pre(mid+1,r,k<<1|1,x,y,X); 114 else return max(get_pre(l,mid,k<<1,x,mid,X),get_pre(mid+1,r,k<<1|1,mid+1,y,X)); 115 } 116 int get_suc(int l,int r,int k,int x,int y,int X){ 117 if(l==x&&r==y) return tree[k].suc(X); 118 int mid=l+((r-l)>>1); 119 if(y<=mid) return get_suc(l,mid,k<<1,x,y,X); 120 else if(x>mid) return get_suc(mid+1,r,k<<1|1,x,y,X); 121 else return min(get_suc(l,mid,k<<1,x,mid,X),get_suc(mid+1,r,k<<1|1,mid+1,y,X)); 122 } 123 int get_kth(int x,int y,int k){ 124 int l=0,r=oo; 125 while(l<r){ 126 int mid=l+((r-l)>>1); 127 int tmp=get_rank(1,n,1,x,y,mid)+1; 128 if(tmp<=k) l=mid+1; 129 else r=mid; 130 } 131 return get_pre(1,n,1,x,y,l); 132 } 133 }T; 134 135 int main() 136 { 137 scanf("%d%d",&n,&q); 138 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 139 T.build_tree(1,n,1); 140 int qry,l,r,k,x,pos; 141 for(int i=1;i<=q;i++){ 142 scanf("%d",&qry); 143 switch(qry){ 144 case 1: 145 scanf("%d%d%d",&l,&r,&x); 146 printf("%d\n",T.get_rank(1,n,1,l,r,x)+1);break; 147 case 2: 148 scanf("%d%d%d",&l,&r,&k); 149 printf("%d\n",T.get_kth(l,r,k));break; 150 case 3: 151 scanf("%d%d",&pos,&x); 152 T.change(1,n,1,pos,x); 153 a[pos]=x;break; 154 case 4: 155 scanf("%d%d%d",&l,&r,&x); 156 printf("%d\n",T.get_pre(1,n,1,l,r,x));break; 157 case 5: 158 scanf("%d%d%d",&l,&r,&x); 159 printf("%d\n",T.get_suc(1,n,1,l,r,x));break; 160 } 161 } 162 return 0; 163 }
2.另一种remove写法
1 #include <cstdio> 2 #include <cstdlib> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn=50000+5,oo=~0u>>1; 7 int n,q; 8 int a[maxn]; 9 struct Treap{ 10 struct node{ 11 node* ch[2]; 12 int v,r,s,c; 13 node(int v,node* t):v(v){ ch[0]=ch[1]=t; r=rand(); s=c=1; } 14 void push_up() { s=ch[0]->s+ch[1]->s+c; } 15 }*root,*null; 16 Treap(){ 17 null=new node(0,NULL); 18 null->c=null->s=0; null->r=oo; 19 root=null; 20 } 21 void rotate(node* &o,bool d){ 22 node* k=o->ch[!d]; o->ch[!d]=k->ch[d]; k->ch[d]=o; 23 o->push_up(); k->push_up(); 24 if(o==root) root=k; 25 o=k; 26 } 27 void insert(node* &o,int x){ 28 if(o==null) o=new node(x,null); 29 else{ 30 if(x==o->v) o->s++, o->c++; 31 else{ 32 bool d=x>o->v; 33 insert(o->ch[d],x); 34 if(o->ch[d]<o) rotate(o,!d); 35 o->push_up(); 36 } 37 } 38 } 39 void remove(node* &o,int x) { 40 if(x==o->v) { 41 if(o->c>1) o->c--,o->s--; 42 else{ 43 bool d=o->ch[1]->r<o->ch[0]->r; 44 if(o->ch[d]==null){ 45 delete o; 46 o=null; 47 } 48 else{ 49 rotate(o,!d); 50 remove(o->ch[!d],x); 51 o->push_up(); 52 } 53 } 54 } 55 else{ 56 bool d=x>o->v; 57 remove(o->ch[d],x); 58 o->push_up(); 59 } 60 } 61 int rank(int x){ 62 int ret=0,s; 63 for(node *t=root;t!=null;){ 64 s=t->ch[0]->s+t->c; 65 if(x>t->v) ret+=s,t=t->ch[1]; 66 else t=t->ch[0]; 67 } 68 return ret; 69 } 70 int pre(int x){ 71 int ret=-oo; 72 for(node* t=root;t!=null;){ 73 if(t->v<x) ret=t->v,t=t->ch[1]; 74 else t=t->ch[0]; 75 } 76 return ret; 77 } 78 int suc(int x){ 79 int ret=oo; 80 for(node* t=root;t!=null;){ 81 if(t->v>x) ret=t->v,t=t->ch[0]; 82 else t=t->ch[1]; 83 } 84 return ret; 85 } 86 }; 87 88 struct Segment_Tree{ 89 Treap tree[maxn<<2]; 90 void build_tree(int l,int r,int k){ 91 for(int i=l;i<=r;i++) tree[k].insert(tree[k].root,a[i]); 92 if(l==r) return; 93 int mid=l+((r-l)>>1); 94 build_tree(l,mid,k<<1); build_tree(mid+1,r,k<<1|1); 95 } 96 int get_rank(int l,int r,int k,int x,int y,int X){ 97 if(l==x&&r==y) return tree[k].rank(X); 98 int mid=l+((r-l)>>1); 99 if(y<=mid) return get_rank(l,mid,k<<1,x,y,X); 100 else if(x>mid) return get_rank(mid+1,r,k<<1|1,x,y,X); 101 else return get_rank(l,mid,k<<1,x,mid,X)+get_rank(mid+1,r,k<<1|1,mid+1,y,X); 102 } 103 void change(int l,int r,int k,int id,int x){ 104 tree[k].remove(tree[k].root,a[id]); 105 tree[k].insert(tree[k].root,x); 106 if(l==r) return; 107 int mid=l+((r-l)>>1); 108 if(id<=mid) change(l,mid,k<<1,id,x); 109 else change(mid+1,r,k<<1|1,id,x); 110 } 111 int get_pre(int l,int r,int k,int x,int y,int X){ 112 if(l==x&&r==y) return tree[k].pre(X); 113 int mid=l+((r-l)>>1); 114 if(y<=mid) return get_pre(l,mid,k<<1,x,y,X); 115 else if(x>mid) return get_pre(mid+1,r,k<<1|1,x,y,X); 116 else return max(get_pre(l,mid,k<<1,x,mid,X),get_pre(mid+1,r,k<<1|1,mid+1,y,X)); 117 } 118 int get_suc(int l,int r,int k,int x,int y,int X){ 119 if(l==x&&r==y) return tree[k].suc(X); 120 int mid=l+((r-l)>>1); 121 if(y<=mid) return get_suc(l,mid,k<<1,x,y,X); 122 else if(x>mid) return get_suc(mid+1,r,k<<1|1,x,y,X); 123 else return min(get_suc(l,mid,k<<1,x,mid,X),get_suc(mid+1,r,k<<1|1,mid+1,y,X)); 124 } 125 int get_kth(int x,int y,int k){ 126 int l=0,r=oo; 127 while(l<r){ 128 int mid=l+((r-l)>>1); 129 int tmp=get_rank(1,n,1,x,y,mid)+1; 130 if(tmp<=k) l=mid+1; 131 else r=mid; 132 } 133 return get_pre(1,n,1,x,y,l); 134 } 135 }T; 136 137 int main() 138 { 139 scanf("%d%d",&n,&q); 140 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 141 T.build_tree(1,n,1); 142 int qry,l,r,k,x,pos; 143 for(int i=1;i<=q;i++){ 144 scanf("%d",&qry); 145 switch(qry){ 146 case 1: 147 scanf("%d%d%d",&l,&r,&x); 148 printf("%d\n",T.get_rank(1,n,1,l,r,x)+1);break; 149 case 2: 150 scanf("%d%d%d",&l,&r,&k); 151 printf("%d\n",T.get_kth(l,r,k));break; 152 case 3: 153 scanf("%d%d",&pos,&x); 154 T.change(1,n,1,pos,x); 155 a[pos]=x;break; 156 case 4: 157 scanf("%d%d%d",&l,&r,&x); 158 printf("%d\n",T.get_pre(1,n,1,l,r,x));break; 159 case 5: 160 scanf("%d%d%d",&l,&r,&x); 161 printf("%d\n",T.get_suc(1,n,1,l,r,x));break; 162 } 163 } 164 return 0; 165 }