二逼平衡树——线段树套平衡树(treap)

Posted JhinLZH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二逼平衡树——线段树套平衡树(treap)相关的知识,希望对你有一定的参考价值。

此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

输入

第一行两个数 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的后继

样例输入

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

样例输出

2 4 3 4 9

提示

n,m<=50000   保证有序序列所有值在任何时刻满足[0,10^8]

这道题相对于普通平衡树就是把所有查询操作从整个数列改为在一个区间里查询,因此需要用线段树来维护区间,然后在区间上完成相应的操作。

线段树套平衡树就是在线段树上的每一个节点建一棵平衡树来维护这个节点所对应区间的信息,因为线段树最多有logn层,每个数在一层只出现一次,所以所有平衡树节点数是nlogn,时间复杂度是O(m*logn^2)。原理就是在线段树上先找到所查区间对应的分区间,在每个分区间节点的平衡树上查找信息再合并。

1、4、5操作不做说明和平衡树一样。3操作就是把这个数删掉再把改完值的数加进去。重点是2操作,需要二分答案(二分k的值),然后用1操作来验证。

树套树代码一般都很长而且不好调试但很好理解。

最后附上代码

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<queue>
  7 #include<vector>
  8 using namespace std;
  9 int n,m;
 10 int tot;
 11 int a[100010];
 12 int l,r,k,opt,x;
 13 struct intree
 14 {
 15     int s[2];
 16     int w;
 17     int r;
 18     int v;
 19     int size;
 20 };
 21 intree treap[2000100];
 22 int inbuild(int k)
 23 {
 24     tot++;
 25     treap[tot].r=rand();
 26     treap[tot].v=k;
 27     treap[tot].size=1;
 28     treap[tot].w=1;
 29     treap[tot].s[0]=treap[tot].s[1]=0;
 30     return tot;
 31 }
 32 void updata(int i)
 33 {
 34     treap[i].size=treap[i].w+treap[treap[i].s[0]].size+treap[treap[i].s[1]].size;
 35 }
 36 void rotate(int &x,int i)
 37 {
 38     int p=treap[x].s[i];
 39     treap[x].s[i]=treap[p].s[i^1];
 40     treap[p].s[i^1]=x;
 41     updata(x);
 42     updata(p);
 43     x=p;
 44 }
 45 void insert(int &x,int k)
 46 {
 47     if(!x)
 48     {
 49         x=inbuild(k);
 50     }
 51     else if(treap[x].v==k)
 52     {
 53         treap[x].w++;
 54     }
 55     else
 56     {
 57         if(treap[x].v<k)
 58         {
 59             insert(treap[x].s[1],k);
 60             if(treap[treap[x].s[1]].r>treap[x].r)
 61             {
 62                 rotate(x,1);
 63             }
 64         }
 65         else
 66         {
 67             insert(treap[x].s[0],k);
 68             if(treap[treap[x].s[0]].r>treap[x].r)
 69             {
 70                 rotate(x,0);
 71             }
 72         }
 73     }
 74     updata(x);
 75 }
 76 void del(int &x,int k)
 77 {
 78     if(treap[x].v<k)
 79     {
 80         del(treap[x].s[1],k);
 81     }
 82     else if(treap[x].v>k)
 83     {
 84         del(treap[x].s[0],k);
 85     }
 86     else
 87     {
 88         if(treap[x].w>1)
 89         {
 90             treap[x].w--;
 91         }
 92         else
 93         {
 94             if(treap[x].s[0]*treap[x].s[1]==0)
 95             {
 96                 x=treap[x].s[0]+treap[x].s[1];
 97             }
 98             else
 99             {
100                 if(treap[treap[x].s[0]].r>treap[treap[x].s[1]].r)
101                 {
102                     rotate(x,0);
103                     del(treap[x].s[1],k);
104                 }
105                 else
106                 {
107                     rotate(x,1);
108                     del(treap[x].s[0],k);
109                 }
110             }    
111         }
112     }
113     if(x)
114     {
115         updata(x);
116     }
117 }
118 int inrank(int x,int k)
119 {
120     if(!x)
121     {
122         return 0;
123     }
124     if(treap[x].v>k)
125     {
126         return inrank(treap[x].s[0],k);
127     }
128     else if(treap[x].v==k)
129     {
130         return treap[treap[x].s[0]].size;
131     }
132     else
133     {
134         return inrank(treap[x].s[1],k)+treap[treap[x].s[0]].size+treap[x].w;
135     }
136 }
137 int inpre(int x,int k)
138 {
139     if(!x)
140     {
141         return -2147483647;
142     }
143     if(treap[x].v>=k)
144     {
145         return inpre(treap[x].s[0],k);
146     }
147     else
148     {
149         return max(treap[x].v,inpre(treap[x].s[1],k));
150     }
151 }
152 int insuf(int x,int k)
153 {
154     if(!x)
155     {
156         return 2147483647;
157     }
158     if(treap[x].v<=k)
159     {
160         return insuf(treap[x].s[1],k);
161     }
162     else
163     {
164         return min(treap[x].v,insuf(treap[x].s[0],k));
165     }
166 }
167 struct outtree
168 {
169     int l;
170     int r;
171     int root;
172 };
173 outtree tree[2000100];
174 void outbuild(int x,int l,int r)
175 {
176     tree[x].l=l;
177     tree[x].r=r;
178     for(int i=l;i<=r;i++)
179     {
180         insert(tree[x].root,a[i]);
181     }
182     if(l!=r)
183     {
184         int mid=(l+r)>>1;
185         outbuild(x*2,l,mid);
186         outbuild(x*2+1,mid+1,r);
187     }
188 }
189 void change(int i,int x,int y)
190 {
191     del(tree[i].root,a[x]);
192     insert(tree[i].root,y);
193     if(tree[i].l==tree[i].r)
194     {
195         return ;
196     }
197     int mid=(tree[i].l+tree[i].r)>>1;
198     if(mid<x)
199     {
200         change(i*2+1,x,y);
201     }
202     else
203     {
204         change(i*2,x,y);
205     }
206 }
207 int outrank(int x,int l,int r,int k)
208 {
209     if(tree[x].l>r||tree[x].r<l)
210     {
211         return 0;
212     }
213     if(tree[x].l>=l&&tree[x].r<=r)
214     {
215         return inrank(tree[x].root,k);
216     }
217     else
218     {
219         return outrank(x*2,l,r,k)+outrank(x*2+1,l,r,k);
220     }
221 }
222 int outsum(int l,int r,int k)
223 {
224     int L=0;
225     int R=1e8;
226     while(L<R)
227     {
228         int mid=(L+R+1)>>1;
229         if(outrank(1,l,r,mid)<k)
230         {
231             L=mid;
232         }
233         else
234         {
235             R=mid-1;
236         }
237     }
238     return R;
239 }
240 int outpre(int x,int l,int r,int k)
241 {
242     if(tree[x].l>r||tree[x].r<l)
243     {
244         return -2147483647;
245     }
246     if(tree[x].l>=l&&tree[x].r<=r)
247     {
248         return inpre(tree[x].root,k);
249     }
250     else
251     {
252         return max(outpre(x*2,l,r,k),outpre(x*2+1,l,r,k));
253     }
254 }
255 int outsuf(int x,int l,int r,int k)
256 {
257     if(tree[x].l>r||tree[x].r<l)
258     {
259         return 2147483647;
260     }
261     if(tree[x].l>=l&&tree[x].r<=r)
262     {
263         return insuf(tree[x].root,k);
264     }
265     else
266     {
267         return min(outsuf(x*2,l,r,k),outsuf(x*2+1,l,r,k));
268     }
269 }
270 int main()
271 {
272     srand(12378);
273     scanf("%d%d",&n,&m);
274     for(int i=1;i<=n;i++)
275     {
276         scanf("%d",&a[i]);
277     }
278     outbuild(1,1,n);
279     for(int i=1;i<=m;i++)
280     {
281         scanf("%d",&opt);
282         if(opt==1)
283         {
284             scanf("%d%d%d",&l,&r,&k);
285             printf("%d\n",outrank(1,l,r,k)+1);
286         }
287         else if(opt==2)
288         {
289             scanf("%d%d%d",&l,&r,&k);
290             printf("%d\n",outsum(l,r,k));
291         }
292         else if(opt==3)
293         {
294             scanf("%d%d",&k,&x);
295             change(1,k,x);
296             a[k]=x;
297         }
298         else if(opt==4)
299         {
300             scanf("%d%d%d",&l,&r,&k);
301             printf("%d\n",outpre(1,l,r,k));
302         }
303         else
304         {
305             scanf("%d%d%d",&l,&r,&k);
306             printf("%d\n",outsuf(1,l,r,k));
307         }
308     }
309     return 0;
310 }

 

以上是关于二逼平衡树——线段树套平衡树(treap)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3196 && luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)

bzoj3196 二逼平衡树——线段树套平衡树

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

bzoj3196 Tyvj 1730 二逼平衡树 线段树套Treap

[TYVJ 1730]二逼平衡树 线段树套平衡树

「luogu3380」模板二逼平衡树(树套树)