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

原文地址:https://www.cnblogs.com/sainsist/p/11160308.html

时间: 2024-10-11 05:12:45

[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)的相关文章

[BZOJ3223] [Tyvj1729] 文艺平衡树 (splay)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数 接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n Output 输出一行n个数字,表示原始序列经过m次变换后的结果 Sample Input 5 3 1 3

[BZOJ3223][tyvj1729]文艺平衡树

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 5356  Solved: 3163 [Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列

[BZOJ3223]文艺平衡树 无旋Treap

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2--n-1,n)  m表示翻转操作次数接下来m行每行两个数[l,r] 数据保证 1<=l<

[您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我们还是用rand()来实现平衡 而无旋treap与treap不同的地方,也是其核心,就是它不旋转用两个新的核心函数:merge函数(合并两棵子树)和split函数(分裂出某棵树的前k个节点,并且作为一棵树返回) 首先看merge函数,它是一个递归实现的过程,先看代码: 1 Treap *merge(

TYVJ1729文艺平衡树

传送门:http://tyvj.cn/Problem_Show.aspx?id=1729 文艺平衡树 From admin 背景 Background 此为平衡树系列第二道:文艺平衡树 描述 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式 InputFormat 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……

【算法学习】Fhq-Treap(无旋Treap)

Treap--大名鼎鼎的随机二叉查找树,以优异的性能和简单的实现在OIer们中广泛流传. 这篇blog介绍一种不需要旋转操作来维护的Treap,即无旋Treap,也称Fhq-Treap. 它的巧妙之处在于只需要分离和合并两种基本操作,就能实现任意的平衡树常用修改操作. 而不需要旋转的特性也使编写代码时不需要考虑多种情况和复杂的父亲儿子关系的更新,同时降低了时间复杂度. 此外,它还可以方便地支持可持久化,实在是功能强大. 接下来系统性地介绍一下无旋Treap的原理和实现,最后讲解一下应用和例题.

模板 - 数据结构 - 无旋Treap / FHQ Treap

普通平衡树: #include<bits/stdc++.h> using namespace std; typedef long long ll; #define ls(p) ch[p][0] #define rs(p) ch[p][1] const int MAXN = 100000 + 5; int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root; void Init() { tot = root = 0; } void Pu

BZOJ3223: Tyvj 1729 文艺平衡树 [splay]

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3595  Solved: 2029[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

Tyvj P1729 文艺平衡树 Splay

题目: http://tyvj.cn/p/1729 P1729 文艺平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第二道:文艺平衡树 描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数