【luogu P6136】普通平衡树(数据加强版)

这篇博客介绍了如何使用替罪羊树解决一道在线平衡树题目,包括插入、删除、查询排名、查询区间元素和找前驱后继等操作。题目对输入进行了编码,需要在解码后处理。文章提供了详细的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

普通平衡树(数据加强版)

题目链接:luogu P6136

题目大意

平衡树模板题的加强版,要求维护一些操作。插入一个数,删除一个数,查询一个数的排名,查询排名一直的数,找前驱后继。
强制在线,范围更大。

思路

这题其实就是 luogu P3369,其实代码跟它差不多。
我那一题写的博客,替罪羊树做法,这题也是用替罪羊树

很明显, 这个就是用平衡树就可以过,但是有些东西要改一下。

首先,要把读入进行解码。
接着,对于询问排名对于的数,如果排名排不到哪里,就要选最后一个,因为排名小于它的最大数就是排名最后的。

然后就好了。
如果不会写替罪羊的,可以看我普通版的博客

代码

//替罪羊

#include<cstdio>
#define alpha 0.7

using namespace std;

struct Tree {
	int l, r, val, fa, num, sum;
}tree[2000001];
struct reTree {
	int val, num;
}retree[2000001];
int n, m, op, x, root, sta[2000001];
int maxn, tot, tott;
int last_answer, final_answer;

bool check(int x) {
	if (!tree[x].num) return 0;
	if (tree[tree[x].l].sum >= (double)(alpha * tree[x].sum)) return 1;
	if (tree[tree[x].r].sum >= (double)(alpha * tree[x].sum)) return 1;
	return 0;
}

void up(int now) {
	tree[now].sum = tree[now].num;
	if (tree[now].l) tree[now].sum += tree[tree[now].l].sum;
	if (tree[now].r) tree[now].sum += tree[tree[now].r].sum;
}

void dfs(int x) {
	sta[++sta[0]] = x;
	if (tree[x].l) dfs(tree[x].l);
	if (tree[x].num) {
		retree[++tott].val = tree[x].val;
		retree[tott].num = tree[x].num;
	}
	tree[x].sum = 0;
	if (tree[x].r) dfs(tree[x].r);
}

int get_new() {
	if (sta[0]) {
		sta[0]--;
		return sta[sta[0] + 1];
	}
	else return ++tot;
}

void make_new(int l, int r, int now, int father) {
	int mid = (l + r) >> 1;
	tree[now].fa = father;
	tree[now].num = retree[mid].num;
	tree[now].val = retree[mid].val;
	tree[now].sum = 1;
	if (l <= mid - 1) {
		tree[now].l = get_new();
		make_new(l, mid - 1, tree[now].l, now);
	}
	else tree[now].l = 0;
	if (r >= mid + 1) {
		tree[now].r = get_new();
		make_new(mid + 1, r, tree[now].r, now);
	}
	else tree[now].r = 0;
	up(now);
}

void rebuild(int x) {
	if (!x) return ;
	tott = 0;
	dfs(x);
	int now = get_new();
	if (x == root) root = now;
	tree[now].fa = tree[x].fa;
	int mid = (1 + tott) >> 1;
	if (retree[mid].val < tree[tree[now].fa].val) tree[tree[now].fa].l = now;
		else tree[tree[now].fa].r = now;
	make_new(1, tott, now, tree[now].fa);
}

void insert(int x, bool need_build) {
	if (root == 0) {
		root = 1;
		tot = 1;
		tree[1] = (Tree){0, 0, x, 0, tree[1].num + 1, tree[1].sum + 1};
		return ;
	}
	
	int now = root;
	while (tree[now].sum) {
		if (x == tree[now].val) {
			tree[now].num++;
			tree[now].sum++;
			return ;
		}
		if (!tree[now].l && x < tree[now].val) break;
		if (!tree[now].r && x > tree[now].val) break;
		tree[now].sum++;
		if (x < tree[now].val) now = tree[now].l;
			else if (x > tree[now].val) now = tree[now].r;
	}
	if (x == tree[now].val) {
		tree[now].num++;
		tree[now].sum++;
		return ;
	}
	
	tree[now].sum++;
	
	int tmp = now;
	if (x < tree[now].val) now = tree[now].l = ++tot;
		else if (x > tree[now].val) now = tree[now].r = ++tot;
	tree[now].num++;
	tree[now].sum++;
	tree[now].val = x;
	if (tmp != now) tree[now].fa = tmp;
	
	int first_fix = 0;
	while (now != root) {
		now = tree[now].fa;
		if (check(now)) first_fix = now;
	}
	if (need_build && first_fix) rebuild(first_fix);
}

int tree_place(int x) {
	int now = root;
	while (tree[now].val != x && tree[now].sum != 0) {
		if (x <= tree[now].val) now = tree[now].l;
			else now = tree[now].r;
	}
	return now;
}

void delete_(int x, int need_build) {
	tree[x].num--;
	tree[x].sum--;
	int first_fix = 0;
	while (x != root) {
		x = tree[x].fa;
		tree[x].sum--;
		if (check(x)) first_fix = x;
	}
	
	if (need_build && first_fix) rebuild(first_fix);
}

int get_rank(int x) {
	insert(x, 0);
	
	int now = tree_place(x);
	
	int re = tree[tree[now].l].sum + 1;
	while (now != root) {
		if (tree[tree[now].fa].r == now)
			re += tree[tree[tree[now].fa].l].sum + tree[tree[now].fa].num;
		now = tree[now].fa;
	}
	
	delete_(tree_place(x), 0);
	
	return re;
}

int get_num(int x) {
	int now = root;
	while (x) {
		if (x <= tree[tree[now].l].sum) now = tree[now].l;
			else if (x <= tree[tree[now].l].sum + tree[now].num) return tree[now].val;
				else {
					x -= tree[tree[now].l].sum + tree[now].num;
					now = tree[now].r;
				}
	}
	return tree[now].fa;
}

int pre(int x) {
	insert(x, 0);
	int need_rank = get_rank(x) - 1;
	delete_(tree_place(x), 0);
	return get_num(need_rank);
}

int suc(int x) {
	insert(x + 1, 0);
	int need_rank = get_rank(x + 1);
	delete_(tree_place(x + 1), 0);
	return get_num(need_rank);
}

int read() {
	int re = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
		re = re * 10 + c - '0';
		c = getchar();
	}
	return re;
}

void write(int x) {
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

int main() {
	n = read();
	m = read();
	
	for (int i = 1; i <= n; i++) {
		x = read();
		insert(x, 1);
	}
	
	for (int i = 1; i <= m; i++) {
		op = read();
		x = read();
		
		x ^= last_answer;//对答案进行解码

		if (op == 1) {
			insert(x, 1);
			continue;
		}
		if (op == 2) {
			delete_(tree_place(x), 1);
			continue;
		}
		if (op == 3) {
			last_answer = get_rank(x);
			final_answer ^= last_answer;
			continue;
		}
		if (op == 4) {
			if (x > tree[root].sum) x = tree[root].sum;//不存在,也就是排名排不到那里,那要求的就是排名最后的
			last_answer = get_num(x);
			final_answer ^= last_answer;
			continue;
		}
		if (op == 5) {
			last_answer = pre(x);
			final_answer ^= last_answer;
			continue;
		}
		if (op == 6) {
			last_answer = suc(x);
			final_answer ^= last_answer;
			continue;
		}
	}
	
	write(final_answer);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值