【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);
}
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\n",ans);
	return 0;
}
时间: 2024-12-28 16:54:02

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

【推导】Codeforces Round #424 (Div. 1, rated, based on VK Cup Finals) A. Office Keys

选择的钥匙一定是连续的,人和钥匙一定从左到右连续对应. 就枚举钥匙区间即可. #include<cstdio> #include<algorithm> using namespace std; int Abs(int x){ return x<0 ? (-x) : x; } int n,K,p,a[1010],ans=2147483647,b[2010]; int main(){ scanf("%d%d%d",&n,&K,&p);

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)E. Cards Sorting

题意:有n个数字,我遍历过去,如果他是当前最小值,就删除,否则放到最后面去,问得遍历多少个数字,(直到所有数字消失 思路:我们保存每个数字的位置,这个数字是否能删除,如果他在上一个数字的最后一个位置后面就可以删除了,那么标记下+树状数组(我这里的y表示的就是上一个数删除的最后一个位置) 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 6 int a[

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Cards Sorting(树状数组)

Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this integer is between 1 and 100?0

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力

Vladimir wants to modernize partitions in his office. To make the office more comfortable he decided to remove a partition and plant several bamboos in a row. He thinks it would be nice if there are n bamboos in a row, and the i-th from the left is a

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 831D) - 贪心 - 二分答案

There are n people and k keys on a straight line. Every person wants to get to the office which is located on the line as well. To do that, he needs to reach some point with a key, take the key and then go to the office. Once a key is taken by somebo

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)

D题fst了,生无可恋.第二场rated的CF,打得精神恍惚 A. Unimodal Array 题意:判断数列是否是单峰的. 像题意那样分为三个阶段随便判一判就好了 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; int n,x[105],part=1; bool f=1; int main() { scanf(&quo

A. Office Keys (from Codeforces Round #424 (Div. 1, rated, based on VK Cup Finals) )

1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 7 int a[150000]; 8 int b[150000]; 9 int dp[1005][1005]; 10 //dp[i][j] 前i个人从前j个药匙中到达终点的最小时间 11 12 int main() 13 { 14 in

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) Problem A - B

Pronlem A In a small restaurant there are a tables for one person and b tables for two persons. It it known that n groups of people come today, each consisting of one or two people. If a group consist of one person, it is seated at a vacant one-seate

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals)D. High Load

题意:出n个点,其中k个叶子节点,问构造出的树最远的两个点最近是多少 思路:以一个点为中心,然后m个伸出,一层层扩散,(n-1)%m==k,如果k==0,即可以平分,长度就是2*(n-1)/m,如果取模为k==1,说明多出一个,+1,其他的话,就是最后一层补k个,但是最长的还是+2 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int n,m; 6 cin>>n>>m; 7 int