WA on #2 求调
查看原帖
WA on #2 求调
1055703
Elhaithan楼主2024/4/21 11:20
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 1;
struct Node{
	int s[2];//左右儿子,s[0]为左儿子,s[1]为右儿子
	int p;//父亲
	int v;//节点权值
	int cnt;//权值出现次数
	int size;//子树大小
	void init(int p1, int v1) {
		p = p1, v = v1;
		cnt = size = 1;
	}
}tr[N];
int n;
int root;//根节点编号
int idx;//节点个数
void pushup(int x) {
	tr[x].size = tr[tr[x].s[0]].size + tr[tr[x].s[1]].size + tr[x].cnt;
}
void rotate(int x) {
	int y = tr[x].p, z = tr[y].p;//获取父亲节点
	int k = tr[y].s[1] == x;//判断是左儿子还是右儿子
	tr[y].s[k] = tr[x].s[k ^ 1];//把 x 的右儿子给 y,作为它的左儿子
	tr[tr[x].s[k ^ 1]].p = y;// x 的右儿子的父亲改为 y
	tr[x].s[k ^ 1] = y;
	tr[y].p = x;
	tr[z].s[tr[z].s[1] == y] = x;
	tr[x].p = z;
	pushup(y), pushup(x);
}
void splay(int x, int k) {//将 x 节点转到目标节点 k 的下面作儿子
	while(tr[x].p != k) {
		int y = tr[x].p, z = tr[y].p;
		if(z != k) //折线形转底节点 x,直线型转中节点 y
			(tr[y].s[0] == x) ^ (tr[z].s[1] == y) ? rotate(x) : rotate(y);
		rotate(x);
	}
	if(k == 0) root = x;//转到根节点做标记
}
void find(int v) {//找到 v 并转到根节点
	int x = root; //从根节点进入
	while(tr[x].s[v > tr[x].v] && v != tr[x].v) //当 x 的儿子节点为空或找到了 v,则退出
		x = tr[x].s[v > tr[x].v];
	splay(x, 0); 
}
int get_pre(int v) {//前驱
	find(v);
	int x = root;
	if(tr[x].v < v) return x;
	x = tr[x].s[0]; //往左子树走
	while(tr[x].s[1]) x = tr[x].s[1]; //左子树中最大的点在其右子树上
	return x;
}
int get_suc(int v) {//后继
	find(v);
	int x = root;
	if(tr[x].v > v) return x;
	x = tr[x].s[1];//往右子树走
	while(tr[x].s[0]) x = tr[x].s[0]; //右子树上最小的点在其左子树上
	return x;
}
void del(int v) {//删除
	int pre = get_pre(v);
	int suc = get_suc(v);
	splay(pre, 0), splay(suc, pre);
	int del = tr[suc].s[0];
	if(tr[del].cnt > 1) { //如果 v 有多个,个数 -1
		tr[del].cnt --;
		splay(del, 0); //更新受影响的子树
	}
	else { //否则直接清空
		tr[suc].s[0] = 0;
		splay(suc, 0); //更新受影响的子树
	}
}
int get_rank(int v) {//排名	
	find(v);
	return tr[tr[root].s[0]].size;
}
int get_val(int k) {//数值
	int x = root;
	while(1) {
		int y = tr[x].s[0]; //取 x 的左儿子
		if(tr[y].size + tr[x].cnt < k) { //如果左子树加根的大小比 k 小,则说明要查询的数在右子树
			k -= tr[y].size + tr[x].cnt; //减去左子树大小
			x = tr[x].s[1]; //往右子树走
		}
		else {
			if(tr[y].size >= k) x = tr[x].s[0]; //若左子树大小比 k 大,说明要查询的数在左子树
			else break; //走不了,说明找到了,退出
		}
	}
	splay(x, 0);
	return tr[x].v;
}
void insert(int v) {//插入
	int x = root, p = 0;// p 为记录当前节点的父节点
	while(x && tr[x].v != v) {//走到空节点或当前节点的值等于插入值则退出
		p = x;
		x = tr[x].s[v > tr[x].v]; //判断往哪个子树走
	}
	if(x) tr[x].cnt ++; //若节点不为空,说明之前插入过此值,个数 +1
	else { //否则新建一个点
		x = ++ idx;
		tr[p].s[v > tr[p].v] = x;
		tr[x].init(p, v);
	}
	splay(x, 0);
}
signed main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	insert(-1e18), insert(1e18);
	cin >> n;
	while(n --) {
		int op, x;
		cin >> op >> x;
		if(op == 1) insert(x);
		if(op == 2) del(x);
		if(op == 3) cout << get_rank(x) << '\n';
		if(op == 4) cout << get_val(x + 1) << '\n';
		if(op == 5) cout << tr[get_pre(x)].v << '\n';
		if(op == 6) cout << tr[get_suc(x)].v << '\n';
	}
	
	return 0;
}

对于以下这份数据

5
1 24
1 25
1 20
3 23
3 23

应输出

2
2

实际输出

2
1
2024/4/21 11:20
加载中...