集訓隨記

Opuntia9622發表於2024-07-16

WBLT

放兩個題的 Code 先。

普通平衡樹(資料加強版)

#include <bits/stdc++.h>
using namespace std;
#define rep(i, x, y) for (int i = (x), ___ = (y); i <= ___; i++)
#define per(i, x, y) for (int i = (x), ___ = (y); i >= ___; i--)
inline int read() {
	char ch = getchar(); int s = 0, f = 1;
	while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return s * f;
}
constexpr int N = 2e6 + 2e5 + 100;
namespace WBLT {
	int tot, ls[N], rs[N], val[N], sz[N];
	constexpr double alpha = 0.292;
	inline void copy(int x, int y) {
		ls[x] = ls[y], rs[x] = rs[y];
		sz[x] = sz[y], val[x] = val[y];
	}
	inline int add(int x, int siz, int lson, int rson) {
		ls[++tot] = lson, rs[tot] = rson;
		sz[tot] = siz, val[tot] = x;
		return tot;
	}
	inline int addfa(int x, int y) { return add(val[y], sz[x] + sz[y], x, y); }
	inline void pushup(int id) {
		if (!ls[id]) return (void)(sz[id] = 1);
		sz[id] = sz[ls[id]] + sz[rs[id]];
		val[id] = val[rs[id]];
	}
	inline void rotate(int id, bool dir) {
		// dir = 0, L -> R
		// dir = 1, R -> L 
		int ori = 0;
		if (!dir) {
			rs[id] = addfa(rs[ls[id]], rs[id]);
			ori = ls[id]; ls[id] = ls[ls[id]];
			copy(ori, rs[id]), rs[id] = ori, tot--;
		} else {
			ls[id] = addfa(ls[id], ls[rs[id]]);
			ori = rs[id]; rs[id] = rs[rs[id]];
			copy(ori, ls[id]), ls[id] = ori, tot--;
		}
	}
	inline void maintain(int id) {
		if (!ls[id]) return ;
		if (sz[ls[id]] > sz[rs[id]]) {
			if (sz[rs[id]] >= sz[id] * alpha) return ;
			if (sz[rs[ls[id]]] >= sz[ls[id]] * (1 - alpha * 2) / (1 - alpha)) rotate(ls[id], 1);
			rotate(id, 0);
		} else {
			if (sz[ls[id]] >= sz[id] * alpha) return ;
			if (sz[ls[rs[id]]] >= sz[rs[id]] * (1 - alpha * 2) / (1 - alpha)) rotate(rs[id], 0);
			rotate(id, 1);
		}
	}
	void insert(int id, int x) {
		if (!ls[id]) {
			ls[id] = add(min(x, val[id]), 1, 0, 0);
			rs[id] = add(max(x, val[id]), 1, 0, 0);
			pushup(id); maintain(id);
			return ;
		}
		if (val[ls[id]] >= x) insert(ls[id], x);
		else insert(rs[id], x);
		pushup(id); maintain(id);
	}
	void erase(int id, int x, int fa = -1) {
		if (!ls[id]) {
			if (val[ls[fa]] == x) copy(fa, rs[fa]);
			else if (val[rs[fa]] == x) copy(fa, ls[fa]);
			return ;
		}
		if (val[ls[id]] >= x) erase(ls[id], x, id);
		else erase(rs[id], x, id);
		pushup(id); maintain(id);
	}
	int rnk(int id, int x) {
		if (!ls[id]) return 1;
		if (val[ls[id]] >= x) return rnk(ls[id], x);
		return rnk(rs[id], x) + sz[ls[id]];
	}
	int kth(int id, int x) {
		if (sz[id] == x) return val[id];
		if (sz[ls[id]] >= x) return kth(ls[id], x);
		return kth(rs[id], x - sz[ls[id]]);
	}
	inline int pre(int rt, int x) { return kth(rt, rnk(rt, x) - 1); }
	inline int suf(int rt, int x) { return kth(rt, rnk(rt, x + 1)); }
}
signed main() {
	#ifndef ONLINE_JUDGE
		freopen("opuntia.in", "r", stdin);
		freopen("opuntia.out", "w", stdout);
	#endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int n = read(), qq = read(), rt = WBLT::add(2e9, 1, 0, 0), ans = 0, Ans = 0;
	while (n--) {
		int x = read();
		WBLT::insert(rt, x);
	}
	while (qq--) {
		int op = read(), x = read() ^ ans;
		if (op == 1) WBLT::insert(rt, x);
		else if (op == 2) WBLT::erase(rt, x);
		else if (op == 3) Ans ^= (ans = WBLT::rnk(rt, x));
		else if (op == 4) Ans ^= (ans = WBLT::kth(rt, x));
		else if (op == 5) Ans ^= (ans = WBLT::pre(rt, x));
		else Ans ^= (ans = WBLT::suf(rt, x));
	}
	cout << Ans;
    return 0;
}

文藝平衡樹

#include <bits/stdc++.h>
using namespace std;
#define rep(i, x, y) for (int i = (x), ___ = (y); i <= ___; i++)
#define per(i, x, y) for (int i = (x), ___ = (y); i >= ___; i--)
inline int read() {
	char ch = getchar(); int s = 0, f = 1;
	while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return s * f;
}
namespace WBLT {
	constexpr int N = 2e5 + 100;
	int tot, ls[N], rs[N], val[N], sz[N]; bool rev[N];
	vector<int> cur;
	constexpr double alpha = 0.25;
	inline void copy(int x, int y) {
		ls[x] = ls[y], rs[x] = rs[y];
		sz[x] = sz[y], val[x] = val[y];
	}
	inline int add(int x, int siz, int lson, int rson) {
		if (cur.size()) {
			int id = cur.back(); cur.pop_back();
			ls[id] = lson, rs[id] = rson;
			sz[id] = siz, val[id] = x;
			return id;
 		}
		ls[++tot] = lson, rs[tot] = rson;
		sz[tot] = siz, val[tot] = x;
		return tot;
	}
	inline int addfa(int x, int y) { return add(val[y], sz[x] + sz[y], x, y); }
	inline void pushup(int id) {
		if (!ls[id]) return (void)(sz[id] = 1);
		sz[id] = sz[ls[id]] + sz[rs[id]];
		val[id] = val[rs[id]];
	}
	inline void pushdown(int id) {
		if (!rev[id] || !ls[id]) return ;
		swap(ls[id], rs[id]);
		rev[ls[id]] ^= 1, rev[rs[id]] ^= 1;
		rev[id] = 0;
	}
	inline void rotate(int id, bool dir) {
		// dir = 0, L -> R
		// dir = 1, R -> L 
		int ori = 0;
		if (!dir) {
			rs[id] = addfa(rs[ls[id]], rs[id]);
			ori = ls[id]; ls[id] = ls[ls[id]];
			copy(ori, rs[id]), rs[id] = ori, tot--;
		} else {
			ls[id] = addfa(ls[id], ls[rs[id]]);
			ori = rs[id]; rs[id] = rs[rs[id]];
			copy(ori, ls[id]), ls[id] = ori, tot--;
		}
	}
	inline void maintain(int id) {
		if (!ls[id]) return ;
		if (min(sz[ls[id]], sz[rs[id]]) >= sz[id] * alpha) return ;
		pushdown(id), pushdown(ls[id]), pushdown(rs[id]);
		if (sz[ls[id]] >= sz[rs[id]]) {
			if (sz[rs[ls[id]]] >= sz[ls[id]] * (1 - alpha * 2) / (1 - alpha)) rotate(ls[id], 1);
			rotate(id, 0); 
		} else {
			if (sz[ls[rs[id]]] >= sz[rs[id]] * (1 - alpha * 2) / (1 - alpha)) rotate(rs[id], 0);
			rotate(id, 1);
		}
	}
	void insert(int id, int x) {
		if (!ls[id]) {
			ls[id] = add(min(x, val[id]), 1, 0, 0);
			rs[id] = add(max(x, val[id]), 1, 0, 0);
			pushup(id); maintain(id);
			return ;
		}
		if (val[ls[id]] >= x) insert(ls[id], x);
		else insert(rs[id], x);
		pushup(id); maintain(id);
	}
	int merge(int x, int y) {
		if (!x || !y) return x ^ y;
		if (min(sz[x], sz[y]) >= (sz[x] + sz[y]) * alpha) return addfa(x, y);
		pushdown(x), pushdown(ls[x]), pushdown(rs[x]);
		pushdown(y), pushdown(ls[y]), pushdown(rs[y]);
		if (sz[x] >= sz[y]) {
			if (sz[ls[x]] >= (sz[x] + sz[y]) * alpha) {
				cur.push_back(x);
				int lson = ls[x], rson = rs[x];
				return merge(lson, merge(rson, y));
			} else {
				cur.push_back(x), cur.push_back(rs[x]);
				int lson = ls[x], lrson = ls[rs[x]], rrson = rs[rs[x]];
				return merge(merge(lson, lrson), merge(rrson, y));
			}
		} else {
			if (sz[rs[y]] >= (sz[x] + sz[y]) * alpha) {
				cur.push_back(y);
				int lson = ls[y], rson = rs[y];
				return merge(merge(x, lson), rson);
			} else {
				cur.push_back(ls[y]), cur.push_back(y);
				int llson = ls[ls[y]], rlson = rs[ls[y]], rson = rs[y];
				return merge(merge(x, llson), merge(rlson, rson));
			}
		}	
	} 
	void split(int id, int k, int &x, int &y) {
		if (!k) return (void)(x = 0, y = id);
		if (!ls[id]) return (void)(x = id, y = 0);
		pushdown(id); cur.push_back(id);
		if (sz[ls[id]] >= k) {
			int rson = rs[id];
			split(ls[id], k, x, y);
			y = merge(y, rson);
		} else {
			int lson = ls[id];
			split(rs[id], k - sz[ls[id]], x, y);
			x = merge(lson, x);
		}
	}
	void print(int id) {
		if (!ls[id]) return (void)(cout << val[id] << ' ');
		pushdown(id); print(ls[id]), print(rs[id]);
	}
}
signed main() {
	#ifndef ONLINE_JUDGE
		freopen("opuntia.in", "r", stdin);
		freopen("opuntia.out", "w", stdout);
	#endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int n = read(), qq = read(), rt = WBLT::add(n--, 1, 0, 0), x, y, z, ans = 0, Ans = 0;
	while (n--) WBLT::insert(rt, n + 1);
	while (qq--) {
		int l = read(), r = read();
		WBLT::split(rt, l - 1, x, y);
		WBLT::split(y, r - l + 1, y, z);
		WBLT::rev[y] ^= 1; 
		rt = WBLT::merge(x, WBLT::merge(y, z));
	}
	WBLT::print(rt);
    return 0;
}

Matrix-Tree 插值

指數分治

貓樹分治