[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 }

 

上一篇:Luogu P3369【模板】普通平衡树 Treap模板


下一篇:[BZOJ 1503]郁闷的出纳员(fhq treap)