FHQTreap刷题记录
- 分裂:如图,按值分裂,u比k大则切黄色的一🔪,此时u接上Y的左子树,然后可见Y的左子树仍然空着,u也递归到其左子树。同理,u比k大则切红色的一🔪,此时u接上X的右子树,然后可见X的右子树仍然空着,u也递归到其右子树。
- 合并:随机切红色和紫色,合并的是切口上面部分,return合并后的根,,比如,如果切红色,那递归合并X的右子树和Y,并且X的右儿子的指针指向X的右子树和Y合并的结果。
BZOJ3224: Tyvj 1728 普通平衡树
- 模板题,代码:
1 #include <bits/stdc++.h> 2 #define nmax 100010 3 4 using namespace std; 5 int s[nmax][2]={0}; 6 int si[nmax]={0}, v[nmax], r[nmax]; 7 int cnt = 0; 8 9 void up(int p){ 10 si[p] = si[ s[p][0] ] + si[ s[p][1] ] + 1; 11 } 12 13 void spilit(int& x, int& y, int k, int u){ 14 if(!u) { x=y=0; return; } 15 if(v[u] <= k){ 16 x = u; 17 spilit(s[x][1], y, k, s[x][1]); 18 }else{ 19 y = u; 20 spilit(x, s[y][0], k, s[y][0]); 21 } 22 up(u); 23 } 24 25 int merge(int x, int y){ 26 if(!x || !y){ return x|y; } 27 if(r[x] > r[y]) { 28 s[x][1] = merge(s[x][1], y); 29 up(x); 30 return x; 31 }else{ 32 s[y][0] = merge(x, s[y][0]); 33 up(y); 34 return y; 35 } 36 } 37 38 int kth(int k, int u){ 39 int ans, t; 40 while(1){ 41 t = si[ s[u][0] ] + 1; 42 if(k == t) { ans = u; break; } 43 else if(k < t) u=s[u][0]; 44 else { u=s[u][1]; k-=t; } 45 } 46 return v[ans]; 47 } 48 49 int newnode(int k){ 50 cnt++; 51 v[cnt] = k; 52 si[cnt] = 1; 53 r[cnt] = rand(); 54 return cnt; 55 } 56 57 int main(){ 58 int n, op, num; 59 cin >> n; 60 int x, y, z, root=0; 61 while(n--){ 62 scanf("%d%d", &op, &num); 63 switch (op) 64 { 65 case 1: 66 z = newnode(num); 67 spilit(x, y, num, root); 68 root = merge( merge(x,z) , y ); 69 break; 70 case 2: 71 spilit(x, y, num, root); 72 spilit(x, z, num-1, x); 73 z = merge(s[z][0], s[z][1]); 74 root = merge( merge(x,z), y ); 75 break; 76 case 3: 77 spilit(x, y, num-1, root); 78 printf("%d\n", si[x]+1); 79 root = merge(x, y); 80 break; 81 case 4: 82 printf("%d\n", kth(num, root) ); 83 break; 84 case 5: 85 spilit(x, y, num-1, root); 86 printf("%d\n", kth(si[x], x) ); 87 root = merge(x, y); 88 break; 89 default: 90 spilit(x, y, num, root); 91 printf("%d\n", kth(1, y) ); 92 root = merge(x, y); 93 break; 94 } 95 } 96 return 0; 97 }