WA on #1 #2
查看原帖
WA on #1 #2
776337
sugawara楼主2023/12/3 13:11

code :

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef  pair<int, int> PII;
const int N = 1e6 + 7;
int n;

struct Node {
	int l, r;  //左右节点编号
	int k;  //键值
	int val;  //随机分配的堆中的编号,不断旋转保证编号大的点一定在编号小的点的上方
	int cnt, size;   //cnt代表k有多少个,size代表以u为根的树有多少个点
} tr[N];

int root, idx;

void pushup(int u) {
	tr[u].size = tr[tr[u].l].size + tr[tr[u].r].size + tr[u].cnt;
}

int new_node(int k) { //新建点
	tr[++idx].k = k;
	tr[idx].val = rand();  //rand函数赋予随机值
	tr[idx].cnt = 1;
	tr[idx].size = 1;
	return idx;  //返回节点编号方便递归建树
}

void zag(int &u) { //左旋函数,看不懂可以画图理解一下
	int q = tr[u].r;
	tr[u].r = tr[q].l;
	tr[q].l = u;
	u = q;
	pushup(tr[u].l);
	pushup(u);
}

void zig(int &u) { //右转函数
	int q = tr[u].l;
	tr[u].l = tr[q].r;
	tr[q].r = u;
	u = q;
	pushup(tr[u].r);
	pushup(u);
}

void build() { //建树,树的初始化
	new_node(-INF), new_node(INF);  //防止越界的哨兵
	root = 1, tr[1].r = 2;
	pushup(root);
	if (tr[1].val < tr[2].val) zag(root);
}

void del(int &u, int k) { //树的删除操作
	if (u == 0) return;  //没有这个点就不操作
	if (tr[u].k == k) { //找到了这个点
		if (tr[u].cnt > 1) tr[u].cnt--;  //这个点的数量大于1就直接减去一个就可以了
		else {
			if (tr[u].l || tr[u].r) { //不是叶子节点
				if (!tr[u].r || tr[tr[u].l].val) { //如果左边有点就把要删除的点通过右转转到右边去,然后通过递归不断旋转直到转到叶子节点后删除
					zig(u);
					del(tr[u].r, k);
				} else { //否则转到左边去
					zag(u);
					del(tr[u].l, k);
				}
			} else //是叶子节点就可以直接删除了
				u = 0;
		}
	} else if (tr[u].k > k) del(tr[u].l, k); //如果没有找到就判断一下在左右两边的哪一边
	else del(tr[u].r, k);//找一下
	pushup(u);//上传更改
}

void insert(int &u, int k) { //点的插入操作
	if (u == 0) u = new_node(k);  //走到0说明当前位置没有点,就把点插在这里
	else {
		if (tr[u].k == k)   //重复点数量直接加1
			tr[u].cnt++;
		else {
			if (tr[u].k > k) { //比当前点的键值大就插入左边
				insert(tr[u].l, k);
				if (tr[tr[u].l].val > tr[u].val) zig(u);  //平衡旋转
			} else { //否则插入右边
				insert(tr[u].r, k);
				if (tr[tr[u].r].val > tr[u].val) zag(u);  //平衡旋转
			}
		}
	}
	pushup(u);//更新节点信息
}

int get_rank(int u, int k) { //求k的位置
	if (u == 0) return 0;//是0随便返回就行
	if (tr[u].k == k) return tr[tr[u].l].size + 1;//相等了那排名应该就是左边的数量加上自己
	if (tr[u].k > k) return get_rank(tr[u].l, k);//大了找左边
	return tr[tr[u].l].size + tr[u].cnt + get_rank(tr[u].r, k);//找右边
}

int get_key(int u, int rank) { //求该位置的值
	if (u == 0) return INF;
	if (tr[tr[u].l].size >= rank) return get_key(tr[u].l, rank);//找左边
	if (tr[tr[u].l].size + tr[u].cnt >= rank) return tr[u].k;//如果满足条件就直接return
	return get_key(tr[u].r, rank - tr[tr[u].l].size - tr[u].cnt);//不然就找右边
}

int get_pr(int u, int k) { //前驱,小于k的最大的数
	if (u == 0) return -INF;
	if (tr[u].k >= k) return get_pr(tr[u].l, k);//找左边
	return max(get_pr(tr[u].r, k), tr[u].k);//可能是右边可能是这个数,所以用个max
}

int get_ne(int u, int k) { //后继,大于k的最小的数
	if (u == 0) return INF;//后继的写法和前驱相反
	if (tr[u].k <= k) return get_ne(tr[u].r, k);
	return min(get_ne(tr[u].l, k), tr[u].k);
}

void solve() {
	build();
	cin >> n;
	while (n--) {
		int op, x;
		cin >> op >> x;
		switch (op) {
			case 1: {
				insert(root, x);
				break;
			}
			case 2: {
				del(root, x);
				break;
			}
			case 3: {
				cout << get_rank(root, x)-1 << endl;
				break;
			}
			case 4: {
				cout << get_key(root, x + 1) << endl;
				break;
			}
			case 5: {
				cout << get_pr(root, x) << endl;
				break;
			}
			case 6: {
				cout << get_ne(root, x) << endl;
				break;
			}
		}
	}
}
int main() {
	solve();
	return 0;
}
2023/12/3 13:11
加载中...