HNOI2017单旋#
- 观察题目的性质,发现单旋最小值或最大值时树的形态只是最值提到根, 原来的部分重新建一下边, 然后插入的时候一定是插入到前驱后继中较深的那一个的子树中, 且其子树对应位置一定非空。所以用\(set\)找前驱后继,树的形态直接用数组维护,线段树维护每个店的深度即可。
#include <bits/stdc++.h>
using std :: set;
using std :: pair;
typedef pair<int, int> Pii;
typedef long long ll;
inline int read(int x = 0, int _f = 0)
{
char c = getchar();
for (; !isdigit(c); c = getchar()) _f |= (c == '-');
for (; isdigit(c); c = getchar()) x = x*10 + c-'0';
return _f? -x : x;
}
template <typename T> bool chkmax(T &a, T b) { return a < b? a = b, true : false; }
template <typename T> bool chkmin(T &a, T b) { return a > b? a = b, true : false; }
const int MAXN = 1e5 + 5;
int M;
int val[MAXN], N;
Pii q[MAXN];
inline int pos(int v)
{
return std :: lower_bound(val + 1, val + N + 1, v) - val;
}
namespace SEGT
{
#define lc (h << 1)
#define rc (lc | 1)
#define mid ((l + r) >> 1)
ll sum[MAXN << 2], tag[MAXN << 2];
inline void push_down(int h, int l, int r)
{
if (tag[h]) {
sum[lc] += tag[h] * (mid - l + 1);
sum[rc] += tag[h] * (r - mid);
tag[lc] += tag[h];
tag[rc] += tag[h];
tag[h] = 0;
}
}
void update(int h, int l, int r, int ql, int qr, int v)
{
if (qr < ql) return ;
if (ql <= l && r <= qr) {
tag[h] += v;
sum[h] += (ll)v * (r - l + 1);
return ;
}
push_down(h, l, r);
if (ql <= mid) update(lc, l, mid, ql, qr, v);
if (qr > mid) update(rc, mid + 1, r, ql, qr, v);
sum[h] = sum[lc] + sum[rc];
}
void modify(int h, int l, int r, int p, int v)
{
if (l == r) {
sum[h] = v;
return ;
}
push_down(h, l, r);
p <= mid? modify(lc, l, mid, p, v) : modify(rc, mid + 1, r, p, v);
sum[h] = sum[lc] + sum[rc];
}
ll query(int h, int l, int r, int p)
{
if (l == r) return sum[h];
push_down(h, l, r);
return p <= mid? query(lc, l, mid, p) : query(rc, mid + 1, r, p);
}
#undef lc
#undef rc
#undef mid
}
set<int> S;
int fa[MAXN], ch[MAXN][2];
int rt;
inline int rotate_min()
{
int u = pos(*S.begin()), depth = SEGT :: query(1, 1, N, u);
if (depth != 1) {
SEGT :: update(1, 1, N, fa[u], N, 1);
SEGT :: modify(1, 1, N, u, 1);
assert(fa[u] != 0);
fa[ch[u][1]] = fa[u];
ch[fa[u]][0] = ch[u][1];
ch[u][1] = rt; fa[rt] = u;
rt = u; fa[rt] = 0;
}
else {
assert(rt == u);
}
return depth;
}
inline int rotate_max()
{
int u = pos(*(--S.end())), depth = SEGT :: query(1, 1, N, u);
if (depth != 1) {
SEGT :: update(1, 1, N, 1, fa[u], 1);
SEGT :: modify(1, 1, N, u, 1);
assert(fa[u] != 0);
fa[ch[u][0]] = fa[u];
ch[fa[u]][1] = ch[u][0];
ch[u][0] = rt; fa[rt] = u;
rt = u; fa[rt] = 0;
}
else {
assert(rt == u);
}
return depth;
}
int main()
{
// freopen("splay.in", "r", stdin);
// freopen("splay.out", "w", stdout);
M = read();
for (int o = 1; o <= M; ++o) {
q[o].first = read();
if (q[o].first == 1) {
q[o].second = read();
val[++N] = q[o].second;
}
}
std :: sort(val + 1, val + N + 1);
for (int o = 1; o <= M; ++o) {
int ty = q[o].first, v = q[o].second;
if (ty == 1) {
auto it = S.lower_bound(v);
int dep1 = it == S.begin()? 0 : SEGT :: query(1, 1, N, pos(*prev(it)));
int dep2 = it == S.end()? 0 : SEGT :: query(1, 1, N, pos(*it));
if (dep1 + dep2 == 0) {
fa[rt = pos(v)] = 0;
}
else if (dep1 > dep2) {
fa[pos(v)] = pos(*prev(it));
assert(ch[pos(*prev(it))][1] == 0);
ch[pos(*prev(it))][1] = pos(v);
}
else if (dep2 > dep1) {
fa[pos(v)] = pos(*it);
assert(ch[pos(*it)][0] == 0);
ch[pos(*it)][0] = pos(v);
}
else {
assert(false);
}
SEGT :: modify(1, 1, N, pos(v), std::max(dep1, dep2) + 1);
S.insert(v);
printf("%d\n", std::max(dep1, dep2) + 1);
}
else if (ty == 2) {
printf("%d\n", rotate_min());
}
else if (ty == 3) {
printf("%d\n", rotate_max());
}
else if (ty == 4) {
printf("%d\n", rotate_min());
int u = pos(*S.begin());
SEGT :: update(1, 1, N, u, N, -1);
S.erase(S.begin());
rt = ch[u][1];
fa[rt] = 0;
ch[u][1] = 0;
}
else {
printf("%d\n", rotate_max());
int u = pos(*(--S.end()));
SEGT :: update(1, 1, N, 1, u, -1);
S.erase((--S.end()));
rt = ch[u][0];
fa[rt] = 0;
ch[u][0] = 0;
}
}
return 0;
}