splay学习

学习新姿势


教程
数组版本的splay
伸展树的基本操作与应用
NOI题解
hdu splay模板题

splay区间翻转问题

bzoj 1756线段树求区间的最大子串

spaly(x)指的是将x节点旋转到根节点。

修复序列

修复序列

ac code

a[1] = a[n+2] 初始化为-inf

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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include <bits/stdc++.h>
using namespace std;
#define inc(i, l, r) for(int i=l; i<=r; i++)
#define midf(l, r) (l+r>>1)
typedef long long ll;
typedef vector <int> vi;
typedef set <int> si;
typedef pair <int, int> pii;
typedef long double ld;
const int MOD = 1e9 + 7;
const int maxn = 2e3+10;
const int maxm = 300009;
const int INF = 1e7;
int a[maxn];
int n, m;
namespace SplayTree
{
#define ls(p) t[p].ch[0]
#define rs(p) t[p].ch[1]
struct node {
int size, sum, mx, lm, rm, v;
int tag, rev;
int f, ch[2];
node() {}
node(int val) {ch[0] = ch[1] = tag = rev = f = 0; size = 1; v = sum = mx = lm = rm = val;}
}t[maxn*4];
int st[maxn], sz, top, root;
int newnode() {return top ? st[top--] : ++sz;}
int wh(int p) {return t[t[p].f].ch[1] == p;}
void init(){
sz = top = root = 0;
}
void rever(int p)
{
if(t[p].tag) return;
t[p].rev ^= 1;
swap(ls(p), rs(p)); swap(t[p].lm, t[p].rm);
}
void paint(int p, int val)
{
t[p].tag = 1; t[p].v = val;
t[p].sum = val * t[p].size;
t[p].lm = t[p].rm = t[p].mx = max(val, t[p].sum);
t[p].rev = 0;
}
void pushdown(int p)
{
if(t[p].rev)
{
if(ls(p)) rever(ls(p));
if(rs(p)) rever(rs(p));
t[p].rev = 0;
}
if(t[p].tag)
{
if(ls(p)) paint(ls(p), t[p].v);
if(rs(p)) paint(rs(p), t[p].v);
t[p].tag = 0;
}
}
void pushup(int p)
{
t[p].size = t[ls(p)].size + t[rs(p)].size + 1;
t[p].sum = t[ls(p)].sum + t[rs(p)].sum + t[p].v;
t[p].mx = max(max(t[ls(p)].mx, t[rs(p)].mx), max(0, t[ls(p)].rm) + t[p].v + max(0, t[rs(p)].lm));
t[p].lm = max(t[ls(p)].lm, t[ls(p)].sum + t[p].v + max(0, t[rs(p)].lm));
t[p].rm = max(t[rs(p)].rm, t[rs(p)].sum + t[p].v + max(0, t[ls(p)].rm));
}
void rotate(int p)
{
int f = t[p].f, g = t[f].f, c = wh(p);
if(g) t[g].ch[wh(f)] = p; t[p].f = g;
t[f].ch[c] = t[p].ch[c ^ 1]; if(t[f].ch[c]) t[t[f].ch[c]].f = f;
t[p].ch[c ^ 1] = f; t[f].f = p;
pushup(f); pushup(p);
}
void Splay(int p, int cur)
{
for(;t[p].f != cur; rotate(p))
if(t[t[p].f].f != cur) rotate(wh(p) == wh(t[p].f) ? t[p].f : p);
if(cur == 0) root = p;
}
void build_tree(int &p, int L, int R, int fa)
{
int mid = midf(L, R);
p = newnode();
t[p] = node(a[mid]);
t[p].f = fa;
if(L == R) return;
if(L < mid) build_tree(ls(p), L, mid - 1, p);
if(mid < R) build_tree(rs(p), mid + 1, R, p);
pushup(p);
}
int Kth(int k)
{
int p = root, lsize = 0;
while(p)
{
pushdown(p);
int cur = lsize + t[ls(p)].size;
if(k == cur + 1) return p;
if(k <= cur) p = ls(p);
else {
lsize = cur + 1;
p = rs(p);
}
}
return -1;
}
void Ins_from_a(int k, int tot)
{
for(int i = 1;i <= tot; ++i) scanf("%d", &a[i]);
int f = Kth(k + 1); Splay(f, 0);
int p = Kth(k + 2); Splay(p, f);
build_tree(ls(p), 1, tot, p);
pushup(p); pushup(f);
}
void erase(int p)
{
if(! p) return;
st[++ top] = p;
erase(ls(p)); erase(rs(p));
}
void Del(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
erase(ls(p)); ls(p) = 0;
pushup(p); pushup(f);
}
void Mak(int k, int tot, int x)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
paint(ls(p), x);
pushup(p); pushup(f);
}
void Rev(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
rever(ls(p));
pushup(p); pushup(f);
}
int Sum(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
return t[ls(p)].sum;
}
int MaxSum(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
return t[ls(p)].mx;
}
};
using namespace SplayTree;
int main()
{
char op[10];
while(scanf("%d%d", &n, &m) == 2)
{
init();
a[1] = -INF, a[n+2] = -INF;
t[0] = node(-INF), t[0].sum = t[0].size = 0;
inc(i, 2, n+1) scanf("%d", &a[i]);
build_tree(root, 1, n+2, 0);
int num = n;
int a, b, c;
for(int i=0; i<m; i++){
scanf("%s", op);
if(op[0] == 'G' &&op[4] == 'S'){
scanf("%d%d", &a, &b);
printf("%d\n", Sum(a, b));
}
else if(op[0] == 'M'&& op[4] == 'S'){
printf("%d\n", t[root].mx);
}
else if(op[0] == 'I'){
scanf("%d%d", &a, &b);
num += b;
Ins_from_a(a, b);
}
else if(op[0] == 'D'){
scanf("%d%d", &a, &b);
num -= 1;
Del(a, b);
}
else if(op[0] == 'M'&&op[5] == 'S'){
scanf("%d%d%d", &a, &b, &c);
Mak(a, b, c);
}
else if(op[0] == 'R'){
scanf("%d%d", &a, &b);
Rev(a, b);
}
}
}
return 0;
}

splay对区间操作模板(线段树建树)

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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
#include <bits/stdc++.h>
# define midf(x, y) ((x + y) >> 1)
using namespace std;
typedef long long ll;
typedef vector <int> vi;
typedef set <int> si;
typedef pair <int, int> pii;
typedef long double ld;
const int MOD = 1e9 + 7;
const int maxn = 300009;
const int maxm = 300009;
const double pi = acos(-1.0);
const double eps = 1e-6;
int a[maxn];
namespace SplayTree
{
#define ls(p) t[p].ch[0]
#define rs(p) t[p].ch[1]
#define inf 0x3f3f3f3f
/*
nampspace SplayTree 清单
结点存储位置: node t[maxn];
size: 包含自己的子树大小
sum: 区间和
mx: 区间最大和
lm: 左连续区间最大和
rm: 右连续区间最大和
v: 区间本身的值
tag: 是否需要将区间更新为 v
rev: 是否需要将区间翻转
f: 父亲结点
ch[0]: 左孩子
ch[1]: 右孩子
node(val): 构造函数,表示该节点的值为 val
函数:
newnode(): 确定新的结点的位置
wh(p): 确定右孩子的父亲是自己?(确定自己有右孩子)
rever(p): 翻转以 p 为根节点的子树
paint(p, val): 将以 p 为根节点的子树的所有值染成 val
pushdown(p): 将以 p 为根节点翻转和染色标记下传
pushup(p): 维护 p 的信息
Splay(p, cur): 将 p 旋转到父亲为 cur 位置上
build_tree(&p, L, R, fa): 建立以 p 为根,父亲为 fa,在[L, R]的 SplayTree
Kth(k): 返回区间序号为k的节点的树的编号,越界返回 -1
Ins_from_a(k, tot): 将 a 数组的 [1, tot] 位置的信息插入到 SplayTree 第 k
位上,(也就是在第 k 位置后面插入一个区间)
erase(p): 删除以 p 为根的子树
Get_Max(x): 求 SplayTree 的右叶节点
Del(k, tot): 删除以 k 开始的 tot 个数
Mak(k, tot, x): 将 k 以后的 tot 个数设为 x
Rev(k, tot): 将 k 以后的 tot 个数翻转
Sum(k, tot): 求 k 以后的 tot 个数的和
Sumall(): 求 [1, n]的区间和
MaxSum(k, tot): 求 [k, k + tot - 1] 的最大子段和
MaxSumall(): 求 [1, n] 的最大子段和
Merge(root1, root2): root2 接到 root1 右子树,要求 root1 无右子树
Travel(x): 以 x 为开始,遍历数组,将遍历的值存到 a[] 数组内
Split( L, R, C): 将 [L, R] 放到第 C 个数后面(C = 0 表示插入到最前面)
构造函数:
SplayTree(n): 建立一棵读入 n 个数的 SplayTree,包含 -inf 结点
*/
struct node {
int size, sum, mx, lm, rm, v;
int tag, rev;
int f, ch[2];
node() {}
node(int val) {ch[0] = ch[1] = tag = rev = f = 0; size = 1; v = sum = mx = lm = rm = val;}
}t[maxn];
int st[maxn], sz, top, root;
int newnode() {return top ? st[top--] : ++sz;}
int wh(int p) {return t[t[p].f].ch[1] == p;}
int tmproot;
void rever(int p)
{
if(t[p].tag) return;
t[p].rev ^= 1;
swap(ls(p), rs(p)); swap(t[p].lm, t[p].rm);
}
void paint(int p, int val)
{
t[p].tag = 1; t[p].v = val;
t[p].sum = val * t[p].size;
t[p].lm = t[p].rm = t[p].mx = max(val, t[p].sum);
t[p].rev = 0;
}
void pushdown(int p)
{
if(t[p].rev)
{
if(ls(p)) rever(ls(p));
if(rs(p)) rever(rs(p));
t[p].rev = 0;
}
if(t[p].tag)
{
if(ls(p)) paint(ls(p), t[p].v);
if(rs(p)) paint(rs(p), t[p].v);
t[p].tag = 0;
}
}
void pushup(int p)
{
t[p].size = t[ls(p)].size + t[rs(p)].size + 1;
t[p].sum = t[ls(p)].sum + t[rs(p)].sum + t[p].v;
t[p].mx = max(max(t[ls(p)].mx, t[rs(p)].mx), max(0, t[ls(p)].rm) + t[p].v + max(0, t[rs(p)].lm));
t[p].lm = max(t[ls(p)].lm, t[ls(p)].sum + t[p].v + max(0, t[rs(p)].lm));
t[p].rm = max(t[rs(p)].rm, t[rs(p)].sum + t[p].v + max(0, t[ls(p)].rm));
}
void rotate(int p)
{
int f = t[p].f, g = t[f].f, c = wh(p);
if(g) t[g].ch[wh(f)] = p; t[p].f = g;
t[f].ch[c] = t[p].ch[c ^ 1]; if(t[f].ch[c]) t[t[f].ch[c]].f = f;
t[p].ch[c ^ 1] = f; t[f].f = p;
pushup(f); pushup(p);
}
void Splay(int p, int cur)
{
for(;t[p].f != cur; rotate(p))
if(t[t[p].f].f != cur) rotate(wh(p) == wh(t[p].f) ? t[p].f : p);
if(cur == 0) root = p;
}
void build_tree(int &p, int L, int R, int fa)
{
int mid = midf(L, R);
p = newnode();
t[p] = node(a[mid]);
t[p].f = fa;
if(L == R) return;
if(L < mid) build_tree(ls(p), L, mid - 1, p);
if(mid < R) build_tree(rs(p), mid + 1, R, p);
pushup(p);
}
int Get_max(int x)
{
pushdown(x);
while(t[x].ch[1])
{
x = t[x].ch[1];
pushdown(x);
}
return x;
}
int Kth(int k)
{
int p = root, lsize = 0;
while(p)
{
pushdown(p);
int cur = lsize + t[ls(p)].size;
if(k == cur + 1) return p;
if(k <= cur) p = ls(p);
else {
lsize = cur + 1;
p = rs(p);
}
}
return -1;
}
void Ins_from_a(int k, int tot) //插入的数值已经放到 a[] 数组中
{
//for(int i = 1;i <= tot; ++i) a[i] = read();
int f = Kth(k + 1); Splay(f, 0);
int p = Kth(k + 2); Splay(p, f);
build_tree(ls(p), 1, tot, p);
pushup(p); pushup(f);
}
void erase(int p)
{
if(! p) return;
st[++ top] = p;
erase(ls(p)); erase(rs(p));
}
void Del(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
erase(ls(p)); ls(p) = 0;
pushup(p); pushup(f);
}
void Mak(int k, int tot, int x)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
paint(ls(p), x);
pushup(p); pushup(f);
}
void Rev(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
rever(ls(p));
pushup(p); pushup(f);
}
int Sum(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
return t[ls(p)].sum;
}
int Sumall()
{
return t[1].sum;
}
int MaxSum(int k, int tot)
{
int f = Kth(k); Splay(f, 0);
int p = Kth(k + tot + 1); Splay(p, f);
return t[ls(p)].mx;
}
int MaxSumall()
{
return t[1].mx;
}
void SplayTree(int n)
{
a[1] = a[n + 2] = -inf;
t[0] = node(-inf); t[0].sum = t[0].size = 0;
build_tree(root, 1, n + 2, 0);
}
void Travel(int x)
{
if(! x)return ;
pushdown(x);
Travel(t[x].ch[0]);
a[tmproot++] = t[x].v;// Check here
Travel(t[x].ch[1]);
}
void Merge(int root1, int root2)
{
t[root1].ch[1] = root2;
t[root2].f = root1;
}
void Split(int L, int R, int C)
{
Splay(Kth(L), 0);
Splay(Kth(R + 2), root);
int root1 = t[t[root].ch[1]].ch[0]; //删除区间[L,R]
t[t[root].ch[1]].ch[0] = 0;
pushup(t[root].ch[1]);
pushup(root);
Splay(Kth(C + 1), 0); //先分裂区间C两边,插入区间[L,R],然后合并
int root2 = t[root].ch[1];
Merge(root, root1);
pushup(root);
Splay(Get_max(root),0);
Merge(root, root2);
pushup(root);
}
#undef ls
#undef rs
#undef inf
};
using namespace SplayTree;
int main()
{
ios :: sync_with_stdio(false);
int n, m;
while(~scanf("%d%d", &n, &m)){
a[1] = a[n+2] = -1e9;
t[0] = node(-1e9); t[0].sum = t[0].size = 0;
for(int i=2; i<=n+1; i++){
a[i] = i-1;
}
build_tree(root, 1, n+2, 0);
int l, r;
for(int i=0; i<m; i++){
scanf("%d%d", &l, &r);
Split(l, l+r-1, 0);
}
Travel(root);
for(int i=1; i<n; i++){
printf("%d ", a[i]);
}
printf("%d\n", a[n]);
}
return 0;
}

splay模板2

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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <bits/stdc++.h>
using namespace std;
#define N 300005
/*
n:表示初始的数字的个数
opt:操作的种类
root:表示树根
sz:表示节点的个数
f[i]:表示i节点的父亲节点
ch[i][2]:i节点的左右孩子
key[i]:表示i节点的值
size[i]:表示左右孩子和自己的数字的个数
cnt[i]:表示i节点这一个节点里面存放了几个数字
支持的查询:
insert(x):插入数字x
find(x):查询数字x的名次
findx(x):查询名次为x的数字
pre(x):查询x的前驱
nxt(x):查询x的后继
del(x):删去x的一个数(多个相同的数字只会删除一个数字)
*/
int n,opt,x,root,sz;
int f[N],ch[N][2],key[N],size[N],cnt[N];
void clear(int x)
{
f[x]=ch[x][0]=ch[x][1]=key[x]=size[x]=cnt[x]=0;
}
int get(int x)
{
return ch[f[x]][1]==x;
}
void update(int x)
{
size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];
}
void rotate(int x)
{
int old=f[x],oldf=f[old],wh=get(x);
ch[old][wh]=ch[x][wh^1];
if (ch[old][wh]) f[ch[old][wh]]=old;
ch[x][wh^1]=old;
f[old]=x;
if (oldf) ch[oldf][ch[oldf][1]==old]=x;
f[x]=oldf;
update(old);
update(x);
}
void splay(int x)
{
for (int fa;fa=f[x];rotate(x))
if (f[fa])
rotate( (get(x)==get(fa))?fa:x );
root=x;
}
void insert(int x)
{
if (!root)
{
root=++sz;
cnt[sz]=size[sz]=1;key[sz]=x;
return;
}
int now=root,fa=0;
while (1)
{
if (x==key[now])
{
cnt[now]++;
update(now);
splay(now);
break;
}
fa=now;
now=ch[now][x>key[now]];
if (!now)
{
++sz;
f[sz]=fa;ch[fa][x>key[fa]]=sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
int find(int x)
{
int now=root,ans=0;
while (1)
{
if (x<key[now]) now=ch[now][0];
else
{
ans+=size[ch[now][0]];
if (x==key[now])
{
splay(now);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
}
}
int findx(int x)
{
int now=root;
while (1)
{
if (x<=size[ch[now][0]]) now=ch[now][0];
else
{
x-=size[ch[now][0]];
if (x<=cnt[now])
{
splay(now);
return key[now];
}
x-=cnt[now];
now=ch[now][1];
}
}
}
int pre()
{
int now=ch[root][0];
while (ch[now][1]) now=ch[now][1];
return now;
}
int nxt()
{
int now=ch[root][1];
while (ch[now][0]) now=ch[now][0];
return now;
}
void del(int x)
{
int wh=find(x);
if (cnt[root]>1)
{
--cnt[root];
update(root);
return;
}
if (!ch[root][0]&&!ch[root][1])
{
clear(root);
root=0;
return;
}
if (!ch[root][0])
{
int oldroot=root;
root=ch[oldroot][1];
f[root]=0;
clear(oldroot);
return;
}
if (!ch[root][1])
{
int oldroot=root;
root=ch[oldroot][0];
f[root]=0;
clear(oldroot);
return;
}
int oldroot=root;
int leftbig=pre();splay(leftbig);
ch[root][1]=ch[oldroot][1];
f[ch[root][1]]=root;
clear(oldroot);
update(root);
return;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:
{
insert(x);
break;
}
case 2:
{
del(x);
break;
}
case 3:
{
int ans=find(x);
printf("%d\n",ans);
break;
}
case 4:
{
int ans=findx(x);
printf("%d\n",ans);
break;
}
case 5:
{
insert(x);
printf("%d\n",key[pre()]);
del(x);
break;
}
case 6:
{
insert(x);
printf("%d\n",key[nxt()]);
del(x);
break;
}
}
}
return 0;
}

未解决的问题

文章目录
  1. 1. 修复序列
    1. 1.1. ac code
  2. 2. splay对区间操作模板(线段树建树)
  3. 3. splay模板2
  4. 4. 未解决的问题
{{ live2d() }}