【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\n",ans);
return 0;
}
【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 namesp ...
- 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 ...
- 【构造】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) B. High Load
让你构造一棵树(给定了总结点数和总的叶子数),使得直径最小. 就先弄个菊花图(周围一圈叶子,中间一个点),然后平均地往那一圈放其他的点即可. #include<cstdio> using ...
- 【贪心】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) A. String Reconstruction
在每个给出的子串的起始位置打个标记,记录的是从这里开始的最长子串. 然后输出的时候就扫,如果遇到开始位置,就从这里开始输出,如果其后被更长的覆盖,就跳转到更长的串进行输出. 如果位置没被覆盖,就输出' ...
- 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 ...
- 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 ...
- 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 ...
- 【树状数组】Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) C. DNA Evolution
题意跟某道我出的等差子序列求最值非常像…… 反正询问的长度只有10种,你就建立10批树状数组,每组的公差是确定的,首项不同. 然后询问的时候只需要枚举询问串的每一位,找找这一位对应哪棵树状数组即可. ...
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)A,B,C
A:链接:http://codeforces.com/contest/831/problem/A 解题思路: 从前往后分别统计递增,相等,递减序列的长度,如果最后长度和原序列长度相等那么就输出yes: ...
随机推荐
- 【HNOI】 c tree-dp
[题目描述]给定一个n个节点的树,每个节点有两个属性值a[i],b[i],我们可以在树中选取一个连通块G,这个连通块的值为(Σa[x])(Σb[x]) x∈G,求所有连通块的值的和,输出答案对1000 ...
- 【Python学习】Jupyter解决单个变量输出问题
使用Jupyter的时候有时候发现,我明明写了好几个变量打印,但是它只显示最后一个.Out只有一个. 但是使用下面的语句.就可以实现多个输出. from IPython.core.interactiv ...
- java===java基础学习(10)---对象构造
重载 如果多个方法有相同的名字,不同的参数,便产生了重载.编译器必须挑选出具体执行哪个方法,他通过用各个方法给出的参数类I型那个与特定方法调用所使用的值类型进行匹配来挑选出相应的方法.如果编译器找不到 ...
- 网络知识===wireshark抓包出现“TCP segment of a reassembled PDU”的解释(载)
网上胡说八道,众说风云,感觉这篇还算靠谱点. 原文链接:http://blog.csdn.net/dog250/article/details/51809566 为什么大家看到这个以后总是会往MSS, ...
- pxc群集搭建
pxc群集搭建 1.环境 Percona-XtraDB 5.7.22-22-29.26-log percona-xtrabackup-24-2.4.12 192.168.99.210:3101(第一节 ...
- python爬虫模块之HTML下载模块
HTML下载模块 该模块主要是根据提供的url进行下载对应url的网页内容.使用模块requets-HTML,加入重试逻辑以及设定最大重试次数,同时限制访问时间,防止长时间未响应造成程序假死现象. 根 ...
- 关于eclipase出现的problems during content assist报错问题
解决办法: 把下面箭头指的地方改为上面箭头的指向
- 查看linux 下进程运行时间(转)
原文地址:http://blog.csdn.net/tspangle/article/details/11731317 可通过ps 来查看,通过参数 -o 来查看 如: ps -eo pid,tty, ...
- FineReport——登录不到决策系统
在不断的测试过程中,可能会造成缓存数据的累积,所以在登录过程中可能会出现登录不到决策系统,而是跳转到某一模板页面 解决方法就是清理缓存或者换一个浏览器测试.
- ES6的新增数据类型:Symbol
简介:Symbol类型是es6新增的一个数据类型,Es5的基本数据类型(undefined,null,Object,function,Number,string) Symbol值通过Symbol函数生 ...