[P3369 【模板】普通平衡树] 平衡树Splay

[P3369 【模板】普通平衡树] 平衡树Splay

一个惨痛的教训

题目

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入 x x x
  2. 删除 x x x数(若有多个相同的数,因只删除一个)
  3. 查询 x x x数的排名(排名定义为比当前数小的数的个数 + 1 +1 +1)
  4. 查询排名为 x x x的数
  5. x x x的前驱(前驱定义为小于 x x x,且最大的数)
  6. x x x的后继(后继定义为大于 x x x,且最小的数)

输入格式

第一行为 n n n,表示操作的个数,下面 n n n行每行有两个数 o p t opt opt x x x o p t opt opt表示操作的序号( 1 ≤ o p t ≤ 6 1≤opt≤6 1opt6 )

输出格式

对于操作 3 , 4 , 5 , 6 3,4,5,6 3,4,5,6每行输出一个数,表示对应答案

输入输出样例

输入 #1

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

输出 #1

106465
84185
492737

说明/提示

【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 5 1\le n \le 10^5 1n105 ∣ x ∣ ≤ 1 0 7 ∣x∣≤10^7 x107

介绍

(有待补充,现在还没有完全理解,只是挂个板子——2020.1.20)

板子

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

const int inf=1e8;
int n;

int read(void);
struct node{int fa,val,tot,siz,ch[2];};
class SPLAY{
	public:
		static const int N=4e5+10;
		int tot,root;
		node t[N];
	
		bool son(int);
		void connect(int,int,int);
		int make(int,int);
		void update(int);
		void rotate(int);
		void Splay(int,int);
		void insert(int);
		int find(int);
		void delet(int);
		int rak(int);
		int kth(int);
		int lower(int);
		int upper(int);
}T;

int main(){
	// clock_t as,bs;
	// as=clock();
	//freopen("P3369_12.in","r",stdin);freopen("test.out","w",stdout);
	n=read();
	while(n--){
		int op=read(),x=read();
		switch(op){
			case 1:T.insert(x);break;
			case 2:T.delet(x);break;
			case 3:printf("%d\n",T.rak(x));break;
			case 4:printf("%d\n",T.kth(x));break;
			case 5:printf("%d\n",T.lower(x));break;
			case 6:printf("%d\n",T.upper(x));break;
		}
	}
	// bs=clock();
	// double h=(double)(bs-as)/CLOCKS_PER_SEC;
	//printf("%lf",h);
	return 0;
}
inline int read(){
	char ch=getchar();
	int x=0,m=1;
	while(!isdigit(ch)){if(ch=='-')m=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*m;
}
inline bool SPLAY::son(int x){
	return x==t[t[x].fa].ch[1];
}
inline void SPLAY::connect(int x,int fa,int son){
	t[x].fa=fa,t[fa].ch[son]=x;
	return;
}
inline int SPLAY::make(int fa,int v){
	t[++tot].fa=fa,t[tot].val=v,t[tot].siz=t[tot].tot=1;
	return tot;
}
inline void SPLAY::update(int x){
	t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].tot;
	return;
}
inline void SPLAY::rotate(int x){
	int Y=t[x].fa,R=t[Y].fa;
	int Yson=son(x),Rson=son(Y);
	connect(t[x].ch[Yson^1],Y,Yson);
	connect(Y,x,Yson^1);
	connect(x,R,Rson);
	update(Y),update(x);
	return;
}
inline void SPLAY::Splay(int x,int to){
	int tmp=t[to].fa;
	while(t[x].fa!=tmp){
		int Y=t[x].fa,R=t[Y].fa;
		if(tmp!=R)son(x)^son(to)?rotate(x):rotate(Y);
		rotate(x);
	}
	if(to==root)root=x;
	return;
}
inline void SPLAY::insert(int x){
	int now=root;
	if(!now)root=make(0,x);
	else{
		while(1){
			++t[now].siz;
			if(t[now].val==x){
				t[now].tot++;
				Splay(now,root);
				return;
			}
			int nxt=x>=t[now].val;
			if(!t[now].ch[nxt]){
				t[now].ch[nxt]=make(now,x);
				Splay(t[now].ch[nxt],root);
				return;
			}
			now=t[now].ch[nxt];
		}
	}
	return;
}
inline int SPLAY::find(int x){
	int now=root;
	while(now){
		if(t[now].val==x){
			Splay(now,root);
			return now;
		}
		int nxt=x>=t[now].val;
		now=t[now].ch[nxt];
	}
	return 0;
}
inline void SPLAY::delet(int x){
	int now=find(x);
	if(!now)return;
	if(t[now].tot>1){
		--t[now].tot,--t[now].siz;
		return;
	}
	if(!t[now].ch[0]||!t[now].ch[1]){
		root=t[now].ch[0]+t[now].ch[1];
		t[root].fa=0;
	}
	else{
		int tmp=t[now].ch[1];
		while(t[tmp].ch[0])tmp=t[tmp].ch[0];
		Splay(tmp,root);
		connect(t[now].ch[0],tmp,0);
		connect(tmp,0,1);
		update(tmp);
	}
	return;
}
inline int SPLAY::rak(int x){
	int now=root,ans=0;
	while(now){
		if(t[now].val==x){
			ans+=t[t[now].ch[0]].siz+1;
			Splay(now,root);
			return ans;
		}
		if(x<t[now].val)now=t[now].ch[0];
		else{
			ans+=t[t[now].ch[0]].siz+t[now].tot;
			now=t[now].ch[1];
		}
	}
	if(now)Splay(now,root);
	return 0;
}
inline int SPLAY::kth(int x){
	int now=root;
	while(1){
		int tmp=t[now].siz-t[t[now].ch[1]].siz;
		if(t[t[now].ch[0]].siz<x&&x<=tmp){
			Splay(now,root);
			return t[now].val;
		}
		if(tmp>x)now=t[now].ch[0];
		else x-=tmp,now=t[now].ch[1];
	}
	Splay(now,root);
	return 0;
}
inline int SPLAY::lower(int x){
	int now=root,ans=-inf;
	while(now){
		if(t[now].val<x&&ans<t[now].val)ans=t[now].val;
		int nxt=x>t[now].val;
		now=t[now].ch[nxt];
	}
	return ans;
}
inline int SPLAY::upper(int x){
	int now=root,ans=inf;
	while(now){
		if(t[now].val>x&&ans>t[now].val)ans=t[now].val;
		int nxt=x>=t[now].val;
		now=t[now].ch[nxt];
	}
	return ans;
}

教训及经验

教训

有史以来交的最多的一次
emmmmm交的很多其实主要原因是没怎么理解,还有就是总是犯一些莫名其妙的小错误。

选择学习模板错误

首先,第一次那几个0和88是找的一个错的模板,它本身就会在最后一个点T掉,更别说我加工过的了。

太懒

要是勤一点多看几遍也许就不用这么受制于模板了。

快读写错了……
inline int read(){
	char ch=getchar();
	int x=0,m=1;
	while(!isdigit(ch))if(ch=='-')m=-1,ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*m;
}

原来我的快读长这个鬼样子↑(T__T)↑
乍一看没什么问题吧(而且以前一直这么写没出过什么问题),但是这组数据

10__//以下划线代替空格
1__2

然后后面就再也不能干什么了
所以经过书润大佬的指点(博客
改成了这个样子

inline int read(){
	char ch=getchar();
	int x=0,m=1;
	while(!isdigit(ch)){if(ch=='-')m=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*m;
}

然后后面T的那两个点(80分程序)就都A了
所以说。。。
我太弱了。

经验

类 class

大概会用class了吧(?)
还有static(?class里面不加过不了编译)

平衡树

历经三天调试,重构三次,终于A了。
对平衡树Splay摸着点皮毛。

不能大意!!!!!

2020.1.20 21:57于石家庄市第二中学

是的是北校区
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值