luogu P3721 [AH2017/HNOI2017]单旋 线段树

版权声明:_ https://blog.csdn.net/lunch__/article/details/84861623

题意

  • 给你一颗单旋的 s p l a y splay 树,要求完成以下操作
    1.插入一个节点
    2.把最小值单旋到根
    3.把最大值单旋到根
    4.2操作后删除最小值
    5.3操作后删除最大值
    要求求出每次操作时操作点的深度

我觉得这题没有那些题解里讲的那么简单啊…

首先看到这题第一个想法就是按题意模拟一颗 s p a l y spaly ,但这样显然会被卡,我们需要发掘一下操作的性质。首先插入节点,手玩几次可以发现一定是插入在前驱后继中深度较大的那个节点,并且前驱后继是连在一起的。然后对于单旋操作,我们发现单旋最小值的时候只有左旋,单旋最大值的时候只有右旋,那么整个树父只有 4 4 个点父子关系发生了变化,并且旋转完以后除了它的子树内的点所有点的深度都加了 1 1 ,删除的话把所有点深度减 1 1 就好了。那么我们可以这样子来考虑,用一个线段树来维护点的深度,用一个 s p a l y spaly 来维护平衡树结构,那么就可以做了。

因为点权互不相同,我们离散化后把点的编号当做权值,用一个 s e t set 维护当前正在 s p a l y spaly 内的所有点来快速查找前驱后继。

1操作我们找到前驱后继后用线段树查询深度就好了
2操作我们首先查询深度,再修改深度,然后修改父子关系,要修改根、最小值,最小值的父亲,最小值的右子树,模拟 r o t a t e rotate 的过程就好了。
3操作同上
4操作只要在2操作后先修改深度再修改根的父子关系就好了
5操作同上

复杂度 O ( n log n ) O(n\log n)

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;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/84861623