版权声明:_ https://blog.csdn.net/lunch__/article/details/84861623
题意
- 给你一颗单旋的
树,要求完成以下操作
1.插入一个节点
2.把最小值单旋到根
3.把最大值单旋到根
4.2操作后删除最小值
5.3操作后删除最大值
要求求出每次操作时操作点的深度
我觉得这题没有那些题解里讲的那么简单啊…
首先看到这题第一个想法就是按题意模拟一颗 ,但这样显然会被卡,我们需要发掘一下操作的性质。首先插入节点,手玩几次可以发现一定是插入在前驱后继中深度较大的那个节点,并且前驱后继是连在一起的。然后对于单旋操作,我们发现单旋最小值的时候只有左旋,单旋最大值的时候只有右旋,那么整个树父只有 个点父子关系发生了变化,并且旋转完以后除了它的子树内的点所有点的深度都加了 ,删除的话把所有点深度减 就好了。那么我们可以这样子来考虑,用一个线段树来维护点的深度,用一个 来维护平衡树结构,那么就可以做了。
因为点权互不相同,我们离散化后把点的编号当做权值,用一个 维护当前正在 内的所有点来快速查找前驱后继。
1操作我们找到前驱后继后用线段树查询深度就好了
2操作我们首先查询深度,再修改深度,然后修改父子关系,要修改根、最小值,最小值的父亲,最小值的右子树,模拟
的过程就好了。
3操作同上
4操作只要在2操作后先修改深度再修改根的父子关系就好了
5操作同上
复杂度
Codes
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct Que {
int x, y;
}Q[N];
int tmp[N], cnt, q;
struct Segment_Tree {
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)
#define lson (ls), (l), (mid)
#define rson (rs), (mid + 1), (r)
int S[N << 2], lazy[N << 2];
void modify(int bh, int l, int r, int z) {
lazy[bh] += z, S[bh] += (r - l + 1) * z;
}
void pushup(int bh) {
S[bh] = S[ls] + S[rs];
}
void pushdown(int bh, int l, int r) {
if (lazy[bh]) {
modify(lson, lazy[bh]);
modify(rson, lazy[bh]);
lazy[bh] = 0;
}
}
void update(int bh, int l, int r, int x, int y, int z) {
if (x <= l && r <= y) modify(bh, l, r, z);
else {
pushdown(bh, l, r);
if (x <= mid) update(lson, x, y, z);
if (y > mid) update(rson, x, y, z);
pushup(bh);
}
}
int query(int bh, int l, int r, int x) {
if (l == r) return S[bh];
pushdown(bh, l, r);
if (x <= mid) return query(lson, x);
return query(rson, x);
}
void setval(int pos, int val) {
update(1, 1, cnt, pos, pos, val - query(1, 1, cnt, pos));
}
}T1;
struct Spaly_Tree {
set<int> S; set<int>::iterator Pre, Sub;
int root, fa[N], ch[N][2];
int newnode(int val, int dad) {
S.insert(val), fa[val] = dad, ch[dad][val > dad] = val;
T1.setval(val, T1.query(1, 1, cnt, dad) + 1);
return T1.query(1, 1, cnt, val);
}
int ins(int val) {
if (!root) return S.insert(root = val), T1.setval(val, 1), 1;
if (*S.begin() > val) return newnode(val, *S.begin());
if (*S.rbegin() < val) return newnode(val, *S.rbegin());
Pre = -- S.lower_bound(val), Sub = S.upper_bound(val);
int dep1 = T1.query(1, 1, cnt, *Pre), dep2 = T1.query(1, 1, cnt, *Sub);
return newnode(val, *(dep1 > dep2 ? Pre : Sub));
}
int splay_min() {
int val = *S.begin(), dep = T1.query(1, 1, cnt, val);
if (val == root) return 1;
T1.update(1, 1, cnt, 1, cnt, 1), T1.update(1, 1, cnt, val, fa[val] - 1, -1), T1.setval(val, 1);
fa[root] = val, ch[fa[val]][0] = ch[val][1], fa[ch[val][1]] = fa[val];
ch[val][1] = root, root = val, fa[root] = fa[0] = 0;
return dep;
}
int splay_max() {
int val = *S.rbegin(), dep = T1.query(1, 1, cnt, val);
if (val == root) return 1;
T1.update(1, 1, cnt, 1, cnt, 1), T1.update(1, 1, cnt, fa[val] + 1, val, -1), T1.setval(val, 1);
fa[root] = val, ch[fa[val]][1] = ch[val][0], fa[ch[val][0]] = fa[val];
ch[val][0] = root, root = val, fa[root] = fa[0] = 0;
return dep;
}
void erase_min() {
int val = root; S.erase(root);
root = ch[val][1], ch[val][1] = fa[root] = 0;
T1.update(1, 1, cnt, 1, cnt, -1);
}
void erase_max() {
int val = root; S.erase(root);
root = ch[val][0], ch[val][0] = fa[root] = 0;
T1.update(1, 1, cnt, 1, cnt, -1);
}
}T2;
int main() {
#ifdef ylsakioi
freopen("3721.in", "r", stdin);
freopen("3721.out", "w", stdout);
#endif
scanf("%d", &q);
for (int i = 1; i <= q; ++ i) {
scanf("%d", &Q[i].x);
if (Q[i].x == 1) {
scanf("%d", &Q[i].y);
tmp[++ cnt] = Q[i].y;
}
}
sort(tmp + 1, tmp + cnt + 1);
for (int i = 1; i <= q; ++ i) {
if (Q[i].x == 1) printf("%d\n", T2.ins(lower_bound(tmp + 1, tmp + cnt + 1, Q[i].y) - tmp));
if (Q[i].x == 2) printf("%d\n", T2.splay_min());
if (Q[i].x == 3) printf("%d\n", T2.splay_max());
if (Q[i].x == 4) printf("%d\n", T2.splay_min()), T2.erase_min();
if (Q[i].x == 5) printf("%d\n", T2.splay_max()), T2.erase_max();
}
return 0;
}