【Splay】Codeforces Round #424 (Div. 1, rated, based on VK Cup Finals) B. Cards Sorting

Splay要支持找最左侧的最小值所在的位置。类似线段树一样处理一下,如果左子树最小值等于全局最小值,就查左子树;否则如果当前节点等于全局最小值,就查当前节点;否则查右子树。

为了统计答案,当然还得维护子树大小的函数。

找到位置以后,直接将左右子树交换即可。不需要打标记。

删除节点时,直接将其前驱(是指序列下标的前驱,就是将待删除节点Splay到根后,左子树的最右节点)Splay到根,将其后继(类似)Splay到根的儿子。

然后将后继的左儿子删除即可。

别忘了及时Maintain();

这份代码的Maintain()时机都很合理,以后不要怀疑了。

但是如果插入是单调的,我这个代码好像有点问题……被卡掉了。于是我就在插入的过程中加入了随机Splay结点到根的操作。就过了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define maxn 100010
#define INF 2147483647
int fa[maxn],val[maxn],c[maxn][2],root,tot,siz[maxn],cnt[maxn],val2[maxn];
int minv[maxn];
void Maintain(int x)
{
	siz[x]=siz[c[x][0]]+siz[c[x][1]]+cnt[x];
	minv[x]=val2[x];
	if(c[x][0]){
		minv[x]=min(minv[x],minv[c[x][0]]);
	}
	if(c[x][1]){
		minv[x]=min(minv[x],minv[c[x][1]]);
	}
}
int Findminp(int x=root){
	while(1){
		if(c[x][0] && minv[c[x][0]]==minv[root]){
			x=c[x][0];
		}
		else if(val2[x]==minv[root]){
			return x;
		}
		else{
			x=c[x][1];
		}
	}
}
void NewNode(int &x,int Fa,int key,int key2)
{
	x=++tot;
	fa[x]=Fa;
	c[x][0]=c[x][1]=0;
	val[x]=key;
	val2[x]=minv[x]=key2;
	siz[x]=cnt[x]=1;
}
void Rotate(int x,bool flag)
{
	int y=fa[x];
//	pushdown(y);
//	pushdown(x);
	c[y][!flag]=c[x][flag];
	fa[c[x][flag]]=y;
	if(fa[y]){
		c[fa[y]][c[fa[y]][1]==y]=x;
	}
	fa[x]=fa[y];
	c[x][flag]=y;
	fa[y]=x;
	Maintain(y);
	Maintain(x);
}
void Splay(int x,int goal)
{
	if(!x || x==goal){
		return;
	}
//	pushdown(x);
	int y;
	while((y=fa[x])!=goal){
		if(fa[y]==goal){
			Rotate(x,c[y][0]==x);
		}
		else{
			if((c[y][0]==x)==(c[fa[y]][0]==y)){
				Rotate(y,c[fa[y]][0]==y);
			}
		  	else{
				Rotate(x,c[y][0]==x);
				y=fa[x];
			}
			Rotate(x,c[y][0]==x);
		}
	}
	Maintain(x);
	if(!goal){
		root=x;
	}
}
int Find(int key,int x=root)
{
	while(c[x][val[x]<key]){
		if(val[x]==key){
			return x;
		}
		x=c[x][val[x]<key];
	}
	return x;
}
void Insert(int key,int key2)
{
	if(!root){
		NewNode(root,0,key,key2);
		return;
	}
	int x=Find(key);
	if(val[x]==key){
		++cnt[x];
		Splay(x,0);
		return;
	}
	NewNode(c[x][val[x]<key],x,key,key2);
	Splay(c[x][val[x]<key],0);
}
int Findmax(int x=root)
{
    while(c[x][1]){
        x=c[x][1];
    }
    return x;
}
int Findmin(int x=root)
{
    while(c[x][0]){
        x=c[x][0];
    }
    return x;
}
//int GetPre(int x)
//{
//    Splay(x,0);
//    return Findmax(c[x][0]);
//}
//int GetNex(int x){
//	Splay(x,0);
//	return Findmin(c[x][1]);
//}
int n,m;
typedef long long ll;
ll ans;
int main(){
	scanf("%d",&n);
	int x;
	srand(233);
	for(int i=1;i<=n;++i){
		scanf("%d",&x);
		Insert(i,x);
		Splay(rand()%i+1,0);
	}
	for(int i=1;i<=n;++i){
		int p=Findminp();
		Splay(p,0);
		ans+=(ll)(siz[c[p][0]]+1);
		swap(c[p][0],c[p][1]);
		int pPre=Findmax(c[p][0]);
		int pNex=Findmin(c[p][1]);
		if(!pPre && pNex){
			root=c[p][1];
			fa[root]=0;
		}
		else if(pPre && !pNex){
			root=c[p][0];
			fa[root]=0;
		}
		else if(pPre && pNex){
			Splay(pPre,0);
			Splay(pNex,pPre);
			c[pNex][0]=0;
			Maintain(pNex);
			Maintain(pPre);
		}
	}
	printf("%I64d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7183336.html