洛谷P3369 【模板】普通平衡树

版权声明:233 https://blog.csdn.net/gmh77/article/details/82692433

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

插入 x x
删除 x x 数(若有多个相同的数,因只删除一个)
查询 x x 数的排名(排名定义为比当前数小的数的个数 + 1 +1 。若有多个相同的数,因输出最小的排名)
查询排名为 x x 的数
x x 的前驱(前驱定义为小于 x x ,且最大的数)
x x 的后继(后继定义为大于 x x ,且最小的数)
输入输出格式
输入格式:
第一行为 n n ,表示操作的个数,下面 n n 行每行有两个数 o p t opt x x o p t opt 表示操作的序号( $ 1 \leq opt \leq 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
说明
时空限制:1000ms,128M
1.n的数据范围: $ n \leq 100000 $
2.每个数的数据范围: [ 10 7 , 10 7 ] [-{10}^7, {10}^7]

#题解
一道裸的平衡树题。。。
就拿来练非旋Treap吧。。。

#code

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define Max 100000
#define max 10000001
#define min -10000001
using namespace std;

int tr[Max+1][2];
int sum[Max+1];
int fa[Max+1];
int heap[Max+1];
int num[Max+1];
bool del[Max+1];
int n,Q,I,i,j,k,l,x,y,X,Fs,Ls,type,root,Find,Find2,now,fa1,fa2;

void up(int t) {sum[t]=sum[tr[t][0]]+sum[tr[t][1]]+1;}

void merge(int Fa,int son,int x,int y)
{
	if (heap[x]<heap[y])
	{
		tr[Fa][son]=x;
		fa[x]=Fa;
		
		if (tr[x][1])
		merge(x,1,tr[x][1],y);
		else
		{
			sum[x]+=sum[y];
			tr[x][1]=y;
			fa[y]=x;
		}
	}
	else
	{
		tr[Fa][son]=y;
		fa[y]=Fa;
		
		if (tr[y][0])
		merge(y,0,x,tr[y][0]);
		else
		{
			sum[y]+=sum[x];
			tr[y][0]=x;
			fa[x]=y;
		}
	}
	
	if (Fa) up(Fa);
}

void split(int Fa1,int Fa2,int t,int k)
{
	if (sum[tr[t][0]]>=k)
	{
		if (!fa1) fa1=t;
		
		if (fa[t])
		{
			tr[fa[t]][tr[fa[t]][1]==t]=0;
			up(fa[t]);
		}
		
		tr[Fa1][0]=t;
		fa[t]=Fa1;
		
		if (k && tr[t][0])
		split(t,Fa2,tr[t][0],k);
		
		if (Fa1) up(Fa1);
	}
	else
	{
		if (!fa2) fa2=t;
		
		if (fa[t])
		{
			tr[fa[t]][tr[fa[t]][1]==t]=0;
			up(fa[t]);
		}
		
		tr[Fa2][1]=t;
		fa[t]=Fa2;
		
		if (tr[t][1])
		split(Fa1,t,tr[t][1],k-sum[tr[t][0]]-1);
		
		if (Fa2) up(Fa2);
	}
}

int find(int t,int k)
{
	if (sum[tr[t][0]]>=k)
	return find(tr[t][0],k);
	else
	if (sum[tr[t][0]]+1==k)
	return num[t];
	else
	return find(tr[t][1],k-sum[tr[t][0]]-1);
}

void find1(int t,int s)
{
	if (tr[t][0] && num[t]>=s)
	find1(tr[t][0],s);
	else
	if (tr[t][1] && num[t]<s)
	find1(tr[t][1],s);
	
	if (num[t]<s)
	{
		Find2+=sum[tr[t][0]]+1;
		
		if (num[t]>Find)
		Find=num[t];
	}
}

void find2(int t,int s)
{
	if (tr[t][1] && num[t]<=s)
	find2(tr[t][1],s);
	else
	if (tr[t][0] && num[t]>s)
	find2(tr[t][0],s);
	
	if (num[t]>s && num[t]<Find)
	Find=num[t];
}

int gf(int t)
{
	for (;fa[t];t=fa[t]);
	return t;
}

int main()
{
	srand(time(NULL));
	
	scanf("%d",&Q);
	fo(i,1,Max)
	{
		heap[i]=rand()*32768+rand();
		sum[i]=1;
	}
	
	I=1;
	n=0;
	now=0;
	for (;Q;Q--)
	{
		scanf("%d%d",&type,&x);
		
		switch (type)
		{
			case 1:
				{
					num[++n]=x;
					
					if (!now)
					{
						now++;
						root=n;
						break;
					}
					
					Find=min;
					Find2=0;
					find1(root,x);
					
					if (!Find2)
					merge(0,0,n,root);
					else
					if (Find2==now)
					merge(0,0,root,n);
					else
					{
						fa1=0,fa2=0;
						split(0,0,root,Find2);
						
						merge(0,0,fa2,n);
						merge(0,0,gf(n),fa1);
					}
					root=gf(n);
					
					now++;
					break;
				}
			case 2:
				{
					Find=min;
					Find2=0;
					find1(root,x+1);
					
					if (Find!=x) break;
					
					Find=min;
					Find2=0;
					find1(root,x);
					
					if (!Find2)
					{
						fa1=0,fa2=0;
						split(0,0,root,1);
						root=fa1;
					}
					else
					if (Find2+1==now)
					{
						fa1=0,fa2=0;
						split(0,0,root,now-1);
						root=fa2;
					}
					else
					{
						fa1=0,fa2=0;
						split(0,0,root,Find2);
						j=fa1,k=fa2;
						
						fa1=0,fa2=0;
						split(0,0,j,1);
						
						merge(0,0,k,fa1);
						root=gf(k);
					}
					
					now--;
					break;
				}
			case 3:
				{
					Find2=0;
					find1(root,x);
					
					printf("%d\n",Find2+1);
					break;
				}
			case 4:
				{
					printf("%d\n",find(root,x));
					break;
				}
			case 5:
				{
					Find=min;
					Find2=0;
					find1(root,x);
					
					printf("%d\n",Find);
					break;
				}
			case 6:
				{
					Find=max;
					find2(root,x);
					
					printf("%d\n",Find);
					break;
				}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/82692433