【BZOJ3065】带插入区间K小值

【题目链接】

【思路要点】

  • 替罪羊树套权值线段树。
  • 时间复杂度\(O(NLog^2N)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	70005
#define MAXV	70005
#define MAXP	20000005
#define ALPHA	0.68
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
void getopt(char &c) {
	c = getchar();
	while (c != 'Q' && c != 'I' && c != 'M')
		c = getchar();
}
struct Segment_Tree {
	int now, root[MAXN];
	int top, mem[MAXP];
	int lc[MAXP], rc[MAXP], sum[MAXP];
	void init(int n) {
		for (int i = 1; i <= n; i++)
			mem[i] = n - i + 1;
		top = n;
	}
	int new_node() {
		int tmp = mem[top--];
		lc[tmp] = rc[tmp] = 0;
		sum[tmp] = 0;
		return tmp;
	}
	void recycle(int x) {
		mem[++top] = x;
	}
	void dfs(int x) {
		if (lc[x]) dfs(lc[x]);
		if (rc[x]) dfs(rc[x]);
		recycle(x);
	}
	void clear(int x) {
		if (root[x]) dfs(root[x]);
		root[x] = 0;
	}
	void modify(int &root, int l, int r, int pos, int delta) {
		if (root == 0) root = new_node();
		sum[root] += delta;
		if (l == r) return;
		int mid = (l + r) / 2;
		if (mid >= pos) modify(lc[root], l, mid, pos, delta);
		else modify(rc[root], mid + 1, r, pos, delta);
	}
	void modify(int x, int v, int d) {
		modify(root[x], 0, MAXV, v, d);
	}
	int query(int k, int len, int *type, int *home) {
		int l = 0, r = MAXV;
		for (int i = 1; i <= len; i++)
			home[i] = root[home[i]];
		while (l < r) {
			int mid = (l + r) / 2;
			int tsum = 0;
			for (int i = 1; i <= len; i++)
				tsum += type[i] * sum[lc[home[i]]];
			if (tsum >= k) {
				r = mid;
				for (int i = 1; i <= len; i++)
					home[i] = lc[home[i]];
			} else {
				l = mid + 1;
				k -= tsum;
				for (int i = 1; i <= len; i++)
					home[i] = rc[home[i]];
			}
		}
		return l;
	}
} SMT;
struct Scapegoat_Tree {
	int root, reroot;
	int len, tindex[MAXN];
	int type[MAXN], home[MAXN];
	int top, mem[MAXN];
	int lc[MAXN], rc[MAXN];
	int index[MAXN], size[MAXN];
	void init(int n) {
		for (int i = 1; i <= n; i++)
			mem[i] = n - i + 1;
		top = n;
	}
	int new_node() {
		int tmp = mem[top--];
		lc[tmp] = rc[tmp] = 0;
		index[tmp] = 0;
		size[tmp] = 0;
		SMT.clear(tmp);
		return tmp;
	}
	void recycle(int x) {
		mem[++top] = x;
	}
	void update(int x) {
		size[x] = 1;
		size[x] += size[lc[x]];
		size[x] += size[rc[x]];
	}
	void dfs(int root) {
		if (root != reroot) recycle(root);
		if (lc[root]) dfs(lc[root]);
		tindex[++len] = index[root];
		if (rc[root]) dfs(rc[root]);
	}
	void rebuild(int root, int l, int r) {
		for (int i = l; i <= r; i++)
			SMT.modify(root, tindex[i], 1);
		int mid = (l + r) / 2;
		index[root] = tindex[mid];
		if (mid > l) {
			lc[root] = new_node();
			rebuild(lc[root], l, mid - 1);
		}
		if (mid < r) {
			rc[root] = new_node();
			rebuild(rc[root], mid + 1, r);
		}
		update(root);
	}
	void rebuild(int root) {
		len = 0;
		dfs(root);
		lc[root] = rc[root] = 0;
		index[root] = size[root] = 0;
		SMT.clear(root);
		rebuild(root, 1, len);
	}
	void index_init(int n, int *a) {
		for (int i = 1; i <= n; i++)
			tindex[i] = a[i];
		root = new_node();
		rebuild(root, 1, n);
	}
	bool unbalance(int root) {
		return max(size[lc[root]], size[rc[root]]) > size[root] * ALPHA + 1;
	}
	void insert(int &root, int pos, int value) {
		if (root == 0) {
			root = new_node();
			index[root] = value;
			size[root] = 1;
			SMT.modify(root, value, 1);
			return;
		}
		SMT.modify(root, value, 1); size[root]++;
		if (pos <= size[lc[root]] + 1) insert(lc[root], pos, value);
		else insert(rc[root], pos - size[lc[root]] - 1, value);
		if (unbalance(root)) reroot = root;
	}
	void insert(int pos, int value) {
		reroot = 0;
		insert(root, pos, value);
		if (reroot) rebuild(reroot);
	}
	int modify(int root, int pos, int value) { /*Return Value: Old Index*/
		SMT.modify(root, value, 1);
		if (pos <= size[lc[root]]) {
			int tmp = modify(lc[root], pos, value);
			SMT.modify(root, tmp, -1);
			return tmp;
		} else {
			pos -= size[lc[root]];
			if (pos == 1) {
				int tmp = index[root];
				index[root] = value;
				SMT.modify(root, tmp, -1);
				return tmp;
			}
			int tmp = modify(rc[root], pos - 1, value);
			SMT.modify(root, tmp, -1);
			return tmp;
		}
	}
	void modify(int pos, int value) {
		modify(root, pos, value);
	}
	void getquery(int root, int l, int r, int t) {
		int mid = size[lc[root]] + 1;
		if (mid > r) getquery(lc[root], l, r, t);
		else if (mid < l) getquery(rc[root], l - mid, r - mid, t);
		else {
			len++; home[len] = root; type[len] = t;
			if (l != 1) getquery(lc[root], 1, l - 1, -t);
			if (r != size[root]) getquery(rc[root], r - size[lc[root]], size[root] - size[lc[root]] - 1, -t);
		}
	}
	int query(int l, int r, int k) {
		len = 0;
		getquery(root, l, r, 1);
		return SMT.query(k, len, type, home);
	}
} SGT;
int num[MAXN];
int main() {
	SMT.init(MAXP - 1);
	SGT.init(MAXN - 1);
	int lastans = 0;
	int n; read(n);
	for (int i = 1; i <= n; i++)
		read(num[i]);
	SGT.index_init(n, num);
	int m; read(m);
	for (int i = 1; i <= m; i++) {
		char opt; int l, r, v;
		getopt(opt);
		if (opt == 'I') {
			read(l), read(v);
			l ^= lastans;
			v ^= lastans;
			SGT.insert(l, v);
		}
		if (opt == 'Q') {
			read(l), read(r), read(v);
			l ^= lastans;
			r ^= lastans;
			v ^= lastans;
			printf("%d\n", lastans = SGT.query(l, r, v));
		}
		if (opt == 'M') {
			read(l), read(v);
			l ^= lastans;
			v ^= lastans;
			SGT.modify(l, v);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/80055821