1. 程式人生 > >luogu P3721 [AH2017/HNOI2017]單旋 線段樹

luogu P3721 [AH2017/HNOI2017]單旋 線段樹

題意

  • 給你一顆單旋的 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;
}