[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)
Posted sainsist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)相关的知识,希望对你有一定的参考价值。
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223
平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护的标准,而处理区间问题时,维护平衡树的应该是每个位置的下标,所以平衡树中序遍历时应该是当前区间的样子。例如:
1 2 3 4 5翻转区间1 3,则中序遍历应该输出3,2,1,4,5。
提供splay和无旋Treap的做法。
splay做法:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e5 + 10; 5 int Siz[maxn], ls[maxn], rs[maxn], pos[maxn], lazy[maxn], root; 6 int cnt; 7 inline void up(int x) 8 Siz[x] = Siz[ls[x]] + Siz[rs[x]] + 1; 9 10 inline void down(int x) 11 if (lazy[x]) 12 swap(ls[x], rs[x]); 13 lazy[ls[x]] ^= 1; 14 lazy[rs[x]] ^= 1; 15 lazy[x] = 0; 16 17 18 void split_size(int x, int siz, int &A, int &B) 19 if (x == 0)return (void)(A = B = 0); 20 down(x); 21 if (siz <= Siz[ls[x]]) 22 B = x, split_size(ls[x], siz, A, ls[x]); 23 else 24 A = x, split_size(rs[x], siz - Siz[ls[x]] - 1, rs[x], B); 25 up(x); 26 27 int Merge(int A, int B) 28 if (A == 0 || B == 0)return A | B; 29 int ans; 30 down(A); 31 down(B); 32 if (pos[A] > pos[B])ans = A, rs[A] = Merge(rs[A], B); 33 else ans = B, ls[B] = Merge(A, ls[B]); 34 up(ans); 35 return ans; 36 37 int build(int l, int r) 38 if (l > r)return 0; 39 int mid = l + r >> 1; 40 ls[mid] = build(l, mid - 1); 41 rs[mid] = build(mid + 1, r); 42 pos[mid] = rand(); 43 up(mid); 44 return mid; 45 46 void dfs(int x) 47 if (x) 48 down(x); 49 dfs(ls[x]); 50 printf("%d ", x); 51 dfs(rs[x]); 52 53 54 int main() 55 int n, m; 56 scanf("%d%d", &n, &m); 57 root = build(1, n); 58 while (m--) 59 int l, r; 60 scanf("%d%d", &l, &r); 61 int A, B, C, D; 62 split_size(root, l - 1, A, B); 63 split_size(B, r - l + 1, C, D); 64 lazy[C] ^= 1; 65 root = Merge(A, Merge(C, D)); 66 67 dfs(root); 68 return 0; 69
无旋Treap做法
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int inf = 2e9; 5 const int maxn = 100010; 6 int ch[maxn][2], siz[maxn], lazy[maxn], fa[maxn], val[maxn]; 7 int a[maxn]; 8 int root, cnt; 9 void pushup(int x) 10 siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1; 11 12 void pushdown(int x) 13 if (lazy[x]) 14 if (ch[x][0])lazy[ch[x][0]] ^= 1; 15 if (ch[x][1])lazy[ch[x][1]] ^= 1; 16 swap(ch[x][0], ch[x][1]); 17 lazy[x] = 0; 18 19 20 void rotate(int x) //将x旋转到x的父亲的位置 21 int y = fa[x]; 22 int z = fa[y]; 23 pushdown(y); pushdown(x); 24 int k = (ch[y][1] == x); 25 ch[z][ch[z][1] == y] = x; 26 fa[x] = z; 27 ch[y][k] = ch[x][k ^ 1]; 28 fa[ch[x][k ^ 1]] = y; 29 ch[x][k ^ 1] = y; 30 fa[y] = x; 31 pushup(y); pushup(x); 32 33 void splay(int x, int goal) //将x旋转为goal的子节点 34 while (fa[x] != goal) 35 int y = fa[x]; 36 int z = fa[y]; 37 if (z != goal) 38 (ch[y][1] == x) ^ (ch[z][1] == y) ? rotate(x) : rotate(y); 39 //如果x和y同为左儿子或者右儿子先旋转y 40 //如果x和y不同为左儿子或者右儿子先旋转x 41 rotate(x); 42 43 if (goal == 0) 44 root = x; 45 46 int build(int l, int r, int f) 47 if (l > r)return 0; 48 int mid = l + r >> 1, now = ++cnt; 49 val[now] = a[mid], fa[now] = f, lazy[now] = 0; 50 ch[now][0] = build(l, mid - 1, now); 51 ch[now][1] = build(mid + 1, r, now); 52 pushup(now); 53 return now; 54 55 int FindK(int root, int k) 56 int now = root; 57 while (1) 58 pushdown(now); 59 if (k <= siz[ch[now][0]]) 60 now = ch[now][0]; 61 else 62 k -= siz[ch[now][0]] + 1; 63 if (k == 0)return now; 64 else now = ch[now][1]; 65 66 67 68 void rever(int l, int r) 69 int ll = FindK(root, l); 70 int rr = FindK(root, r + 2); 71 splay(ll, 0); 72 splay(rr, ll); 73 pushdown(root); 74 lazy[ch[ch[root][1]][0]] ^= 1; 75 76 void dfs(int x) 77 pushdown(x); 78 if (ch[x][0])dfs(ch[x][0]); 79 if (val[x] != inf && val[x] != -inf) 80 printf("%d ", val[x]); 81 if (ch[x][1])dfs(ch[x][1]); 82 83 int main() 84 int n, m; 85 scanf("%d%d", &n, &m); 86 for (int i = 1; i <= n; i++) 87 a[i + 1] = i; 88 a[1] = -inf, a[n + 2] = inf; 89 root = build(1, n + 2, 0); 90 while (m--) 91 int l, r; 92 scanf("%d%d", &l, &r); 93 rever(l, r); 94 95 dfs(root); 96 //system("pause"); 97
以上是关于[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3223: Tyvj 1729 文艺平衡树(splay翻转操作)