引言

Splay是一种支持插入、删除、区间翻转、查询等操作的数据结构,在省选/NOI及以上比赛中有着非常广泛的应用。而LCT(Link-Cut-Tree)这种数据结构是Splay的一个“加强版“,其使用Splay作为辅助树,使用LCT我们可以维护动态的森林。

Splay

yyb的模板好强呀!

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
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <climits>
using namespace std;
const int maxn=500050;
int n,tot,root;
inline int read() {
char c=' ';int v=0,f=1;
while(c<'0'||c>'9') {c=getchar();if(c=='-') f=-1;}
while(c>='0'&&c<='9') {v=v*10+c-'0';c=getchar();}
return v*f;
}
struct Splay {
int ch[2];
int dad;
int cnt;
int val;
int sz;
}t[maxn];
inline void pushup(int u) {
t[u].sz=t[t[u].ch[0]].sz+t[t[u].ch[1]].sz+t[u].cnt;
}
inline void rotate(int x) {
int y=t[x].dad;
int z=t[y].dad;
int k=t[y].ch[1]==x;
t[z].ch[t[z].ch[1]==y]=x;
t[x].dad=z;
t[y].ch[k]=t[x].ch[k^1];
t[t[x].ch[k^1]].dad=y;
t[x].ch[k^1]=y;
t[y].dad=x;
pushup(y);pushup(x);
}
inline void splay(int x,int goal) {
while(t[x].dad!=goal) {
int y=t[x].dad;
int z=t[y].dad;
if(z!=goal) (t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
rotate(x);
}
if(goal==0) root=x;
}
inline void insert(int x) {
int u=root,dad=0;
while(u && t[u].val!=x) {
dad=u;
u=t[u].ch[x>t[u].val];
}
if(u) t[u].cnt++;
else {
u=++tot;
if(dad) t[dad].ch[x>t[dad].val]=u;
t[tot].ch[0]=0;t[tot].ch[1]=0;
t[tot].dad=dad;t[tot].val=x;
t[tot].cnt=1;t[tot].sz=1;
}
splay(u,0);
}
inline void find(int x) {
int u=root;
if(!u) return;
while(t[u].ch[x>t[u].val] && x!=t[u].val)
u=t[u].ch[x>t[u].val];
splay(u,0);
}
inline int Next(int x,int f) {
find(x);
int u=root;
if((t[u].val>x && f)||(t[u].val<x && !f)) return u;
u=t[u].ch[f];
while(t[u].ch[f^1]) u=t[u].ch[f^1];
return u;
}
inline void Delete(int u) {
int last=Next(u,0);
int nxt=Next(u,1);
splay(last,0);splay(nxt,last);
int del=t[nxt].ch[0];
if(t[del].cnt>1) {
t[del].cnt--;
splay(del,0);
}
else t[nxt].ch[0]=0;
}
inline int kth(int x) {
int u=root;
if(t[u].sz<x) return false;
while(25) {
int y=t[u].ch[0];
if(x>t[y].sz+t[u].cnt) {
x-=t[y].sz+t[u].cnt;
u=t[u].ch[1];
} else {
if(t[y].sz>=x) u=y;
else return t[u].val;
}
}
}
const int inf=INT_MAX;
int main() {
insert(-inf);
insert(+inf);
n=read();
for(int i=1;i<=n;i++) {
int opt=read();
if(opt==1) insert(read());
else if(opt==2) Delete(read());
else if(opt==3) {
find(read());
printf("%d\n",t[t[root].ch[0]].sz);
}
else if(opt==4) printf("%d\n",kth(read()+1));
else if(opt==5) printf("%d\n",t[Next(read(),0)].val);
else if(opt==6) printf("%d\n",t[Next(read(),1)].val);
}
return 0;
}

LCT