灵异现象
查看原帖
灵异现象
167697
BartAllen楼主2024/8/13 20:23

为何这个fhq代码开O2就全RE,不开O2就AC

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;

int n, tot, root;

struct FHQ {
	int l, r;
	int val, key, size;
} t[N];

int New(int x) {
	tot++;
	t[tot].l = t[tot].r = 0, t[tot].size = 1;
	t[tot].val = x, t[tot].key = rand();
	return tot;
}

void update(int p) {
	t[p].size = t[t[p].l].size + t[t[p].r].size + 1;
}

// 权值分裂,返回以 L 和 R 为根的两棵树
void split(int p, int x, int &L, int &R) {
	if (p == 0) {	// 到达叶子,递归返回
		L = R = 0;
		return;
	}
	if (t[p].val <= x) {	// 本节点比 x 小,到右子树上找
		L = p;	// 左树的根是本节点
		split(t[p].r, x, t[p].r, R);	// 通过右子树传回新的子节点
	}
	else {
		R = p;
		split(t[p].l, x, L, t[p].l);
	}
	update(p);
}

// 合并以 L 和 R 为根的两棵树,返回一棵树的根
int merge(int L, int R) {
	if (L == 0 || R == 0) return L + R;	// 到达叶子,若 L 等于 0,就是返回 L+R=R 
	if (t[L].key > t[R].key) {	// 左树 L 优先级大于右树 R,则 L 节点是父节点
		t[L].r = merge(t[L].r, R);	// 合并 R 和 L 的右儿子,并更新 L 的右儿子
		update(L);
		return L;	// 返回合并后的根 L
	}
	else {
		t[R].l = merge(L, t[R].l);
		update(R);
		return R;
	}
}

int Insert(int x) {
	int L, R;
	split(root, x, L, R);
	root = merge(merge(L, New(x)), R);
}

int Remove(int x) {
	int L, R, p;
	split(root, x, L, R);	// 小于等于 x 的树和大于 x 的树
	split(L, x - 1, L, p);	// 小于 x 的树和等于 x 的树
	p = merge(t[p].l, t[p].r);	// 合并 x=p 的左右两子树,相当于删除 x
	root = merge(merge(L, p), R);
}

void get_rank_by_val(int x) {
	int L, R;
	split(root, x - 1, L, R);	// 小于 x 的树和大于等于 x 的树
	cout << t[L].size + 1 << endl;
	root = merge(L, R);	// 恢复
}

int get_val_by_rank(int p, int k) {
	if (k == t[t[p].l].size + 1) return p;	// 这个数为根
	if (k <= t[t[p].l].size) return get_val_by_rank(t[p].l, k);	// 在左子树
	if (k > t[t[p].l].size) return get_val_by_rank(t[p].l, k - t[t[p].l].size - 1);	// 在右子树
}

void get_pre(int x) {
	int L, R;
	split(root, x - 1, L, R);
	cout << t[get_val_by_rank(L, t[L].size)].val << endl;
	root = merge(L, R);
}

void get_next(int x) {
	int L, R;
	split(root, x, L, R);
	cout << t[get_val_by_rank(R, 1)].val << endl;
	root = merge(L, R);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	srand(time(NULL));
	cin >> n;
	while (n--) {
		int opt, x;
		cin >> opt >> x;
		switch (opt) {
			case 1:
				Insert(x);
				break;
			case 2:
				Remove(x);
				break;
			case 3:
				get_rank_by_val(x);
				break;
			case 4:
				cout << t[get_val_by_rank(root, x)].val << endl;
				break;
			case 5:
				get_pre(x);
				break;
			case 6:
				get_next(x);
				break;
		}
	}
	return 0;
}
2024/8/13 20:23
加载中...