平衡树

平衡树

1、可以维护一个数在数组中的排名,排名为 \(x\) 的数,一个数的前驱和后驱。

2、模版:洛谷P8747洛谷P6136

3、查询和修改的时间复杂度:\(O(logn)\)

template<typename T>
struct Splay{
	struct node{
		int fa;
		int cnt;
		int siz;
		T val;
		int ch[2];
		
		node(int fa = 0, int cnt = 0, int siz = 0, T val = T{})
        : fa(fa), cnt(cnt), siz(siz), val(val) {
            ch[0] = ch[1] = 0;
        }
		
		#define fa_(x) tree[x].fa
		#define cnt_(x) tree[x].cnt
		#define siz_(x) tree[x].siz
		#define val_(x) tree[x].val
		#define c0_(x) tree[x].ch[0]
		#define c1_(x) tree[x].ch[1]
	};
	
	int root = 0, tot = 0;
	vector<node> tree;
	
	Splay() {
        tree.push_back(node());
    }
	
	inline void maintain(int x) {
        siz_(x) = siz_(c0_(x)) + siz_(c1_(x)) + cnt_(x);
    }
	
	inline bool get(int x) {
        return x == c1_(fa_(x));
    }
	
	inline void clear(int x) {
        tree[x] = node();
    }
	
	inline void rotate(int x) {
		int y = fa_(x), z = fa_(y), chk = get(x);
		if (chk) c1_(y) = c0_(x), (c0_(x) ? fa_(c0_(x)) = y : 0), c0_(x) = y;
		else c0_(y) = c1_(x), (c1_(x) ? fa_(c1_(x)) = y : 0), c1_(x) = y;
		
		fa_(y) = x;
		fa_(x) = z;
		if (z) (y == c0_(z) ? c0_(z) = x : c1_(z) = x);
		maintain(y);
		maintain(x);
	}
	
	inline void splay(int x) {
		for (int f = fa_(x); f = fa_(x), f; rotate(x))
			if (fa_(f)) rotate(get(x) == get(f) ? f : x);
		
		root = x;
	}
	
	inline void ins(T val) {
		if (!root) {
			root = ++tot;
			tree.push_back(node(0, 1, 1, val));
			return;
		}
		
		int cur = root, f = 0;
		while (1) {
			if (val_(cur) == val) {
				cnt_(cur)++;
				maintain(cur);
				maintain(f);
				splay(cur);
				break;
			}
			
			f = cur;
			cur = val_(cur) > val ? c0_(cur) : c1_(cur);
			if (!cur) {
				++tot;
				tree.push_back(node(f, 1, 1, val));
				val < val_(f) ? c0_(f) = tot : c1_(f) = tot;
				maintain(cur);
				maintain(f);
				splay(tot);
				break;
			}
		}
	}
	
	inline int rhk(T val) {
		int res = 0, cur = root;
		while (1) {
			if (val < val_(cur)) {
				cur = c0_(cur);
			} else {
				res += siz_(c0_(cur));
				if (val == val_(cur)) {
					splay(cur);
					return res + 1;
				}
				res += cnt_(cur);
				cur = c1_(cur);
			}
		}
	}
	
	inline T kth(int x) {
		int cur = root;
		while (1) {
			if (c0_(cur) && x <= siz_(c0_(cur))) {
				cur = c0_(cur);
			} else {
				x -= siz_(c0_(cur)) + cnt_(cur);
				if (x <= 0) {
					splay(cur);
					return val_(cur);
				}
				cur = c1_(cur);
			}
		}
	}
	
	inline int pre_() {
		int cur = c0_(root);
		if (!cur) return cur;
		while (c1_(cur)) cur = c1_(cur);
		splay(cur);
		return cur;
	}
	
	inline int nxt() {
		int cur = c1_(root);
		if (!cur) return cur;
		while (c0_(cur)) cur = c0_(cur);
		splay(cur);
		return cur;
	}
	
	inline void del(int val) {
		rhk(val);
		if (cnt_(root) > 1) {
			cnt_(root)--;
			maintain(root);
			return;
		}
		
		if (!c0_(root) && !c1_(root)) {
			clear(root);
			root = 0;
			return;
		}
		
		if (!c0_(root)) {
			int cur = root;
			root = c1_(root);
			fa_(root) = 0;
			clear(cur);
			return;
		}
		
		if (!c1_(root)) {
			int cur = root;
			root = c0_(root);
			fa_(root) = 0;
			clear(cur);
			return;
		}
		
		int cur = root, x = pre_();
		fa_(c1_(cur)) = x;
		c1_(x) = c1_(cur);
		clear(cur);
		maintain(root);
	}
};

void solve() {
	int q;
	read(q);
	Splay<int> t;
	while (q--) {
		int opt, x;
		read(opt, x);
		if (opt == 1) {
			t.ins(x);
		} else if (opt == 2) {
			t.del(x);
		} else if (opt == 3) {
			t.ins(x);
			printf("%d\n", t.rhk(x));
			t.del(x);
		} else if (opt == 4) {
			printf("%d\n", t.kth(x));
		} else if (opt == 5) {
			t.ins(x);
			printf("%d\n", t.val_(t.pre_()));
			t.del(x);
		} else {
			t.ins(x);
			printf("%d\n", t.val_(t.nxt()));
			t.del(x);
		}
	}
}
posted @ 2024-08-15 02:38  grape_king  阅读(18)  评论(0)    收藏  举报