Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P5055 【模板】可持久化文艺平衡树

P5055 【模板】可持久化文艺平衡树

在一些实现中, merge 函数的实现中是不新加点的,因为一些特殊性质使得每次 merge 使用的点都是恰好之前 split 的,但是尽量多增加点是一定不会错的。具体地,如果所有相等的权值都记在一个点上,那么是可以不必新加点的。特别地,如果用平衡树维护序列的顺寻,那么每个位置一定只有一个数,是可以不必新加点的。

空间消耗巨大,一定要建立空间回收机制。

查看代码
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <cstdio>
#include <queue>
#include <ctime>
#include <cstdlib>
#include <algorithm>
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0';
flag && (x = ~x + 1);
}
template <class Type, class ...rest>
void read (Type &x, rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar('0' + x % 10);
}
typedef long long L;
const int N = 2e5 + 10, M = 5e7 + 10;
struct Node
{
bool rev;
int s[2], v, w, sz;
L sum;
void init (int k)
{ s[0] = s[1] = 0, sum = v = k, w = rand(), sz = 1; }
} tr[M];
int m, rt[N];
queue <int> trash;
int get () { int t = trash.front(); trash.pop(); return t; }
void clone (int &x) { int t = get(); tr[t] = tr[x]; x = t; }
void pushup (int x)
{
tr[x].sz = tr[tr[x].s[0]].sz + tr[tr[x].s[1]].sz + 1;
tr[x].sum = tr[tr[x].s[0]].sum + tr[tr[x].s[1]].sum + tr[x].v;
}
void pushdown (int x)
{
if (!tr[x].rev) return;
tr[x].rev = false;
swap(tr[x].s[0], tr[x].s[1]);
if (tr[x].s[0])
clone(tr[x].s[0]), tr[tr[x].s[0]].rev ^= 1;
if (tr[x].s[1])
clone(tr[x].s[1]), tr[tr[x].s[1]].rev ^= 1;
}
int merge (int x, int y)
{
if (!x || !y) return x + y;
if (tr[x].w < tr[y].w)
{
// clone(x);
pushdown(x);
tr[x].s[1] = merge(tr[x].s[1], y);
pushup(x);
return x;
}
else
{
// clone(y);
pushdown(y);
tr[y].s[0] = merge(x, tr[y].s[0]);
pushup(y);
return y;
}
}
void split (int u, int t, int &x, int &y)
{
if (!u) return void(x = y = 0);
clone(u);
pushdown(u);
int k = tr[tr[u].s[0]].sz + 1;
if (t < k) y = u, split(tr[u].s[0], t, x, tr[u].s[0]);
else x = u, split(tr[u].s[1], t - k, tr[u].s[1], y);
pushup(u);
}
void insert (int &u, int t, int k)
{
int x, y, z;
split(u, t, x, y);
tr[z = get()].init(k);
u = merge(merge(x, z), y);
}
void remove (int &u, int t)
{
int x, y, z;
split(u, t, x, z);
split(u, t - 1, x, y);
trash.push(y);
u = merge(x, z);
}
void reverse (int &u, int l, int r)
{
int x, y, z;
split(u, r, x, z);
split(x, l - 1, x, y);
tr[y].rev ^= 1;
u = merge(merge(x, y), z);
}
L query (int &u, int l, int r)
{
int x, y, z;
split(u, r, x, z);
split(x, l - 1, x, y);
L res = tr[y].sum;
u = merge(merge(x, y), z);
return res;
}
int main ()
{
srand(time(NULL));
for (int i = 1; i < M; ++i) trash.push(i);
read(m);
L last = 0;
for (int i = 1, pre, op; i <= m; ++i)
{
read(pre, op);
rt[i] = rt[pre];
if (op == 1)
{
L t, k; read(t, k);
t ^= last, k ^= last;
insert(rt[i], t, k);
}
else if (op == 2)
{
L t; read(t);
t ^= last;
remove(rt[i], t);
}
else if (op == 3)
{
L l, r; read(l, r);
l ^= last, r ^= last;
reverse(rt[i], l, r);
}
else if (op == 4)
{
L l, r; read(l, r);
l ^= last, r ^= last;
write(last = query(rt[i], l, r)), puts("");
}
}
return 0;
}