二逼平衡树——线段树套平衡树(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的后继
样例输入
样例输出
提示
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][Tyvj 1730][二逼平衡树] (线段树套treap)