维护一颗初始为空的单旋Splay,需要支持五种操作:

  1. 插入一个值并查询此节点深度
  2. 查询最小值节点的深度并将其单旋至根
  3. 查询最大值节点的深度并将其单旋至根
  4. 查询最小值节点的深度,将其单旋至根后删除
  5. 查询最大值节点的深度,将其单旋至根后删除

根的深度为1

m100000m \le 100000

Luogu P3721

Solution

这道题只要稍微手玩一下找找规律还是比较容易想到的

由于这颗树性质以及查询、修改的东西都比较神奇,可以发现(以下均以最小值为例)把最小值xx旋至根深度实际上只是将xx的右子树的所有节点深度-1,再将除xx之外的所有节点的深度+1;父子关系也只有xx 之间有变化(具体见代码)

有了这个性质就非常好维护了

直接用set维护每个点的前驱后继,用线段树维护每个点深度。在具体实现(处理fa[]fa[]数组)上稍微有一些细节。

Code

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
#include <bits/stdc++.h>

#define x first
#define y second
#define y1 Y1
#define y2 Y2
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long LL;
typedef pair<int, int> pii;

template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }

inline void proc_status()
{
ifstream t ("/proc/self/status");
cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) <<endl;
}

inline int read ()
{
int sum = 0, fl = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
return sum * fl;
}

const int Maxn = 1e5 + 100;

int N, M, B[Maxn], root, ch[Maxn][2], fa[Maxn];
pii A[Maxn];

set <int> S;
set <int> :: iterator it;

namespace SEG
{
#define ls Tree[root << 1]
#define rs Tree[root << 1 | 1]
#define lson root << 1, l, mid
#define rson root << 1 | 1, mid + 1, r
struct tree
{
int sum, tag;
}Tree[Maxn << 2];

inline void push_up (int root) { Tree[root].sum = ls.sum + rs.sum; }

inline void push_down (int root, int l, int r, int mid)
{
if (!Tree[root].tag) return ;
ls.tag += Tree[root].tag;
rs.tag += Tree[root].tag;
ls.sum += Tree[root].tag * (mid - l + 1);
rs.sum += Tree[root].tag * (r - mid);
Tree[root].tag = 0;
}

inline void update (int root, int l, int r, int x, int y, int z)
{
if (x <= l && r <= y) { Tree[root].sum += z * (r - l + 1); Tree[root].tag += z; return ; }
int mid = l + r >> 1;
push_down (root, l, r, mid);
if (x <= mid) update (lson, x, y, z);
if (y > mid) update (rson, x, y, z);
push_up (root);
}

inline void modify (int root, int l, int r, int x, int z)
{
if (l == r) { Tree[root].sum = z; Tree[root].tag = 0; return ; }
int mid = l + r >> 1;
push_down (root, l, r, mid);
if (x <= mid) modify (lson, x, z);
else modify (rson, x, z);
push_up (root);
}

inline int query (int root, int l, int r, int x)
{
if (l == r) return Tree[root].sum;
int mid = l + r >> 1;
push_down (root, l, r, mid);
if (x <= mid) return query (lson, x);
else return query (rson, x);
}
}

inline void link (int x, int f, int dir) { ch[f][dir] = x; fa[x] = f;}

inline int Insert (int x)
{
it = S.insert(x).x;
if (!root) { root = x; SEG :: modify (1, 1, N, x, 1); return 1; }
if (it != S.begin())
{
if (!ch[*(--it)][1]) link (x, *it, 1);
++it;
}
if (!fa[x]) link (x, *(++it), 0);
int ans = SEG :: query (1, 1, N, fa[x]) + 1;
SEG :: modify (1, 1, N, x, ans);
return ans;
}

inline int Query_min ()
{
int x = *S.begin(), ans = SEG :: query (1, 1, N, x);
if (x == root) return 1;
if (fa[x] != x + 1) SEG :: update (1, 1, N, x + 1, fa[x] - 1, -1);
SEG :: update (1, 1, N, 1, N, 1);
link (ch[x][1], fa[x], 0), link (root, x, 1);
root = x;
SEG :: modify (1, 1, N, x, 1);
return ans;
}

inline int Query_max ()
{
int x = *S.rbegin(), ans = SEG :: query (1, 1, N, x);
if (x == root) return 1;
if (fa[x] != x - 1) SEG :: update (1, 1, N, fa[x] + 1, x - 1, -1);
SEG :: update (1, 1, N, 1, N, 1);
link (ch[x][0], fa[x], 1), link (root, x, 0);
root = x;
SEG :: modify (1, 1, N, x, 1);
return ans;
}

inline void Del_min ()
{
SEG :: update (1, 1, N, 1, N, -1);
S.erase(root);
root = ch[root][1], fa[root] = 0;
}

inline void Del_max ()
{
SEG :: update (1, 1, N, 1, N, -1);
S.erase(root);
root = ch[root][0], fa[root] = 0;
}

inline void Solve ()
{
for (int i = 1; i <= M; ++i)
{
if (A[i].x == 1) printf("%d\n", Insert (A[i].y));
else if (A[i].x == 2) printf("%d\n", Query_min());
else if (A[i].x == 3) printf("%d\n", Query_max());
else if (A[i].x == 4) printf("%d\n", Query_min()), Del_min();
else if (A[i].x == 5) printf("%d\n", Query_max()), Del_max();
}
}

inline void Input ()
{
M = read();
for (int i = 1; i <= M; ++i)
{
A[i].x = read();
if (A[i].x == 1) A[i].y = B[++N] = read();
}
sort(B + 1, B + N + 1), N = unique (B + 1, B + N + 1) - B - 1;
for (int i = 1; i <= M; ++i) if (A[i].x == 1) A[i].y = lower_bound (B + 1, B + N + 1, A[i].y) - B;
}

int main()
{
#ifdef hk_cnyali
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif
Input();
Solve();
return 0;
}