Skip to content

洛谷 - P3391 【模板】文艺平衡树

检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

#题面

#题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列。

其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 15\ 4\ 3\ 2\ 1,翻转区间是 [2,4][2, 4] 的话,结果是 5 2 3 4 15\ 2\ 3\ 4\ 1

#输入格式

第一行两个正整数 n,mn, m,表示序列长度与操作个数。序列中第 ii 项初始为 ii。 接下来 mm 行,每行两个正整数 l,rl, r,表示翻转的区间。

#输出格式

输出一行 nn 个正整数,表示原始序列经过 mm 次变换后的结果。

#输入输出样例

样例输入 #1

5 3
1 3
1 3
1 4

样例输出 #1

4 3 2 1 5

#数据范围与约定

对于 100%100\% 的数据,1n,m1000001 \le n, m \leq 1000001lrn1 \le l \le r \le n

#思路

前置知识:无旋 Treap 学习笔记

当翻转 [l,r][l, r] 区间时,先分裂出 [1,r][1, r][r+1,size][r + 1, \mathit{size}] 两个区间,再从 [1,r][1, r] 中分裂出 [1,l1][1, l - 1][l,r][l, r] 两个区间。将 [l,r][l, r] 区间打标记后再合并即可。

最后按照中序遍历输出即为答案。

#代码

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <cstdlib>
#include <iostream>

using std::cin;
using std::cout;
#define endl '\n'

const int N = 1e5 + 5;

int n, m, l, r, root, cnt;

struct node {
int l, r, s, v, k;
bool d;

node()
: l(0), r(0), s(0), v(0), d(false), k(rand()) {}
node(int _v)
: l(0), r(0), s(1), v(_v), d(false), k(rand()) {}
} tr[N];

void pushup(int u) {
tr[u].s = tr[tr[u].l].s + tr[tr[u].r].s + 1;
}

void pushdown(int u) {
if (tr[u].d) {
tr[u].d = false;
tr[tr[u].l].d ^= 1;
tr[tr[u].r].d ^= 1;
std::swap(tr[u].l, tr[u].r);
}
}

int build(int l, int r) {
if (l > r) return 0;
int mid = l + r >> 1;
int p = ++cnt;
tr[p] = node(mid - 1);
tr[p].l = build(l, mid - 1);
tr[p].r = build(mid + 1, r);
pushup(p);
return p;
}

std::pair<int, int> split(int p, int k) {
if (!p) return std::make_pair(0, 0);
pushdown(p);
if (k <= tr[tr[p].l].s) {
auto o = split(tr[p].l, k);
tr[p].l = o.second;
pushup(p);
o.second = p;
return o;
}
auto o = split(tr[p].r, k - tr[tr[p].l].s - 1);
tr[p].r = o.first;
pushup(p);
o.first = p;
return o;
}

int merge(int x, int y) {
if (!x || !y) return x | y;
pushdown(x);
pushdown(y);
if (tr[x].k > tr[y].k) {
tr[x].r = merge(tr[x].r, y);
pushup(x);
return x;
}
tr[y].l = merge(x, tr[y].l);
pushup(y);
return y;
}

void reserve(int l, int r) {
auto x = split(root, r + 1);
auto y = split(x.first, l);
tr[y.second].d ^= 1;
root = merge(merge(y.first, y.second), x.second);
}

void print(int p) {
if (!p) return;
pushdown(p);
print(tr[p].l);
if (1 <= tr[p].v && tr[p].v <= n) {
cout << tr[p].v << ' ';
}
print(tr[p].r);
}

int main() {
std::ios::sync_with_stdio(false);
cin >> n >> m;
root = build(1, n + 2);
while (m--) {
cin >> l >> r;
reserve(l, r);
}
print(root);
cout << endl;
return 0;
}