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\n",ans);
return 0;
}

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

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

    选择的钥匙一定是连续的,人和钥匙一定从左到右连续对应. 就枚举钥匙区间即可. #include<cstdio> #include<algorithm> using namesp ...

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

    E. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  3. 【构造】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) B. High Load

    让你构造一棵树(给定了总结点数和总的叶子数),使得直径最小. 就先弄个菊花图(周围一圈叶子,中间一个点),然后平均地往那一圈放其他的点即可. #include<cstdio> using ...

  4. 【贪心】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) A. String Reconstruction

    在每个给出的子串的起始位置打个标记,记录的是从这里开始的最长子串. 然后输出的时候就扫,如果遇到开始位置,就从这里开始输出,如果其后被更长的覆盖,就跳转到更长的串进行输出. 如果位置没被覆盖,就输出' ...

  5. 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 ...

  6. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Office Keys(思维)

    Office Keys time limit per test 2 seconds memory limit per test 256 megabytes input standard input o ...

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

    http://codeforces.com/contest/831 A. Unimodal Array time limit per test 1 second memory limit per te ...

  8. 【树状数组】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) C. DNA Evolution

    题意跟某道我出的等差子序列求最值非常像…… 反正询问的长度只有10种,你就建立10批树状数组,每组的公差是确定的,首项不同. 然后询问的时候只需要枚举询问串的每一位,找找这一位对应哪棵树状数组即可. ...

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

    A:链接:http://codeforces.com/contest/831/problem/A 解题思路: 从前往后分别统计递增,相等,递减序列的长度,如果最后长度和原序列长度相等那么就输出yes: ...

随机推荐

  1. hdu 1150 Machine Schedule(二分匹配,简单匈牙利算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1150 Machine Schedule Time Limit: 2000/1000 MS (Java/ ...

  2. spring boot web 入门

    ① 新建一个maven项目. ② pom中parent设为 spring-boot-starter-parent .建议使用最新的 RELEASE 版本.否则可能需要设置 <repositori ...

  3. python进行机器学习(五)之模型打分

    一.画出模型的残差值分布情况 #!/usr/bin/python import pandas as pd import numpy as np import csv as csv import mat ...

  4. 无缝衔接demo

    如题. <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" con ...

  5. python基础===字符串切片

    字符串的子串可以通过切片标志来表示:两个由冒号隔开的索引. >>> word 'HelpA' >>> word[4] 'A' >>> word[0 ...

  6. x64dbg

    https://x64dbg.com/ https://github.com/x64dbg/x64dbg https://sourceforge.net/projects/x64dbg/files/s ...

  7. mysql 5.6在gtid复制模式下复制错误,如何跳过??

    mysql 5.6在gtid复制模式下复制错误,如何跳过?? http://www.xuchanggang.cn/archives/918.html

  8. OC 06 Block、数组高级

    主要内容: ⼀.Block语法 ⼆.Block使⽤ 三.Block实现数组排序 Block简介 Block:块语法,本质上是匿名函数(没有名称的函数) 标准C⾥面没有Block,C语⾔言的后期扩展版本 ...

  9. mysql innodb 数据表不存在

    方法一: https://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html 修改my.cnf文件 [mysqld] innodb ...

  10. maven设置打jar包并引入依赖包

    --------------------------------------------------------方法一:将jar包和项目打在一起---------------------------- ...