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

     无旋treap做法

     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     system("pause");
    69     return 0;
    70 }
  • 相关阅读:
    模仿outlook快捷方式栏的一个控件
    买了一本书《Programming pearls》编程珠玑(88上的数学题目(1))
    一个IE动画图标的小例子
    对水波特效实现原理的解释
    向量空间的几何变换
    一个简单Led控件
    【转载】配置(visual studio.net已检测到指定的web服务器运行的不是asp.net1.1版)
    最近学习ASP2.0相关的几个小问题(非创新性文章)
    一道c的面试题,大数相乘。
    Led控件(2)——Led显示屏模拟
  • 原文地址:https://www.cnblogs.com/sainsist/p/11160308.html
Copyright © 2020-2023  润新知