题目链接: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 }