OI萌新刚学1ms,求条
查看原帖
OI萌新刚学1ms,求条
800543
NirvanaCeleste楼主2024/10/31 21:16
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100,INF = 10000010;
inline void read(int& x){
	int y = 0,w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9'){y = y * 10 + ch - '0';ch = getchar();}
	x = y * w;
}
void write(int x){
	if(x < 0) x=-x,putchar('-');
	if(x > 9) write(x/10);
	putchar(x%10+'0');
}
int n,tot,root;
struct node{
	int l,r;
	int cnt,siz,vlu,rnd;
}t[maxn];
inline int creat(int vlu){
	t[++tot].vlu = vlu;
	t[tot].cnt = t[tot].siz = 1;
	t[tot].rnd = rand();
	return tot;
}
inline void update(int p){t[p].siz = t[t[p].l].siz + t[t[p].r].siz + t[p].cnt;}
inline void zig(int& p){//左儿子向右转  
	int q = t[p].l;
	t[p].l = t[q].r,t[q].r = p;
	p = q;
	update(t[p].r),update(p);
}
inline void zag(int& p){//右儿子向左转 
	int q = t[p].r;
	t[p].r = t[q].l,t[q].l = p;
	p = q;
	update(t[p].l),update(p);
}
void insert(int& p,int vlu){
	if(!p){
		p = creat(vlu);
		return;
	}
	if(vlu == t[p].vlu){
		t[p].cnt++;
		update(p);
		return;
	}
	if(vlu > t[p].vlu){
		insert(t[p].r,vlu);
		if(t[p].rnd < t[t[p].r].rnd) zag(p);//注意判断 是否需要旋转 
	}
	if(vlu < t[p].vlu){
		insert(t[p].l,vlu);
		if(t[p].rnd < t[t[p].l].rnd) zig(p);
	}
	update(p);
	return;
}
void cut(int& p,int vlu){
	if(!p) return;
	if(vlu == t[p].vlu){
		if(t[p].cnt > 1){
			t[p].cnt--;
			update(p);//注意这里要更新一下 
			return;
		}
		if(t[p].l || t[p].r){//不是叶子节点 先旋转 
			if(!t[p].r || t[t[p].l].rnd > t[t[p].r].rnd) zig(p),cut(t[p].r,vlu);//p变成它曾经左儿子的右儿子 
			else zag(p),cut(t[p].l,vlu);//不直接删除 是因为无法确定旋转顺序 
		}
		else p = 0;
		return;
	}
	if(vlu < t[p].vlu) cut(t[p].l,vlu);
	else cut(t[p].r,vlu);
	update(p);
	return;
}
int getrankbyvlu(int p,int vlu){
	if(!p) return 0;
	if(vlu == t[p].vlu) return t[t[p].l].siz;//
	if(vlu < t[p].vlu) return getrankbyvlu(t[p].l,vlu);//
	else return getrankbyvlu(t[p].r,vlu) + t[t[p].l].siz + t[p].cnt;//
}
int getvlubyrank(int p,int rank){
	if(!p) return INF;
	if(t[t[p].l].siz >= rank) return getvlubyrank(t[p].l,rank);//t[t[p].l].siz >= rank
	else if(t[t[p].l].siz + t[p].cnt < rank) return getvlubyrank(t[p].r,rank - t[t[p].l].siz - t[p].cnt);
	//not <= 
	else return t[p].vlu;//
}
int getpre(int vlu){
	int res = -INF;
	int p = root;
	while(p){
		if(vlu == t[p].vlu){
			if(t[p].l){
				p = t[p].l;
				while(t[p].r) p = t[p].r;
				res = t[p].vlu;
			}
//			return res;
//有可能不存在子树 
			break;
		}
		if(t[p].vlu < vlu && t[p].vlu > res) res = t[p].vlu;//有可能 vlu 并不在原序列出现 所以更新 
		if(vlu < t[p].vlu) p = t[p].l;
		if(vlu > t[p].vlu) p = t[p].r;
	}
	return res;
}
int getnxt(int vlu){
	int res = INF;
	int p = root;
	while(p){
		if(vlu == t[p].vlu){
			if(t[p].r){
				p = t[p].r;
				while(t[p].l) p = t[p].l;
				res = t[p].vlu;
			}
//			return res;
//有可能不存在子树
			break;
		}
		if(t[p].vlu > vlu && t[p].vlu < res) res = t[p].vlu;//有可能 vlu 并不在原序列出现 所以更新 
		if(vlu < t[p].vlu) p = t[p].l;
		if(vlu > t[p].vlu) p = t[p].r;
	}
	return res;
}
int main(){
//	freopen("1.txt","r",stdin);
	read(n);
	int opt,x;
	while(n--){
		read(opt),read(x);
		if(opt == 1) insert(root,x);
		if(opt == 2) cut(root,x);
		if(opt == 3) write(getrankbyvlu(root,x) + 1),putchar('\n');
		if(opt == 4) write(getvlubyrank(root,x)),putchar('\n');
		if(opt == 5) write(getpre(x)),putchar('\n');
		if(opt == 6) write(getnxt(x)),putchar('\n');
	}
	return 0;
}

一定要在建树的时候插入一个INF和-INF的空节点吗???

2024/10/31 21:16
加载中...