BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)

描述


http://www.lydsy.com/JudgeOnline/problem.php?id=3196

可以处理区间问题的平衡树.

 

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

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可能为负数

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 }
View Code

 

 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 }
View Code

 

posted @ 2016-05-11 22:52  晴歌。  阅读(203)  评论(0编辑  收藏  举报