2018牛客网暑期ACM多校训练营(第三场) H - Shuffle Cards - [splay伸展树][区间移动][区间反转]
题目链接:https://www.nowcoder.com/acm/contest/141/C
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld
题目描述
To prove that, Eddy wants to shuffle cards and tries to predict the final order of the cards. Actually, Eddy knows only one way to shuffle cards that is taking some middle consecutive cards and put them on the top of rest. When shuffling cards, Eddy just keeps repeating this procedure. After several rounds, Eddy has lost the track of the order of cards and believes that the assumption he made is wrong. As Eddy's friend, you are watching him doing such foolish thing and easily memorizes all the moves he done. Now, you are going to tell Eddy the final order of cards as a magic to surprise him.
Eddy has showed you at first that the cards are number from 1 to N from top to bottom.
For example, there are 5 cards and Eddy has done 1 shuffling. He takes out 2-nd card from top to 4-th card from top(indexed from 1) and put them on the top of rest cards. Then, the final order of cards from top will be [2,3,4,1,5].
输入描述:

输出描述:
Output one line contains N space-separated integers indicating the final order of the cards from top to bottom.
输入例子:
5 1
2 3
输出例子:
2 3 4 1 5
-->
输入
5 1
2 3
输出
2 3 4 1 5
输入
5 2
2 3
2 3
输出
3 4 1 2 5
输入
5 3
2 3
1 4
2 4
输出
3 4 1 5 2
题意:
给出一个1~n的数字序列,给出m次操作,每次操作会将以第p个数字为开始的连续s个数字拿出来放到整个序列的开头,求m次操作完成后的序列。
题解:
用splay来搞区间问题:https://www.cnblogs.com/dilthey/p/9379652.html#splay-5
可以直接先区间移动的函数,也可以使用三次区间反转来完成区间移动。
AC代码:
#include<bits/stdc++.h>
#define Key_value ch[ch[root][1]][0]
using namespace std;
const int maxn=1e5+; int n,m; /******************************** splay - st ********************************/
int root,nodecnt;
int par[maxn],ch[maxn][];
int key[maxn],size[maxn];
bool rev[maxn];
void NewNode(int &x,int p,int k)
{
x=++nodecnt;
par[x]=p;
ch[x][]=ch[x][]=;
key[x]=k;
size[x]=;
rev[x]=;
}
void Update_Rev(int x)
{
if(x==) return;
swap(ch[x][],ch[x][]);
rev[x]^=;
}
void Pushup(int x)
{
size[x]=size[ch[x][]]+size[ch[x][]]+;
}
void Pushdown(int x)
{
if(rev[x])
{
Update_Rev(ch[x][]);
Update_Rev(ch[x][]);
rev[x]=;
}
}
void Rotate(int x,int type) //旋转,0为左旋zag,1为右旋zig
{
int y=par[x];
Pushdown(y); Pushdown(x); //先把y的标记向下传递,再把x的标记往下传递
ch[y][!type]=ch[x][type]; par[ch[x][type]]=y;
if(par[y]) ch[par[y]][(ch[par[y]][]==y)]=x;
par[x]=par[y];
ch[x][type]=y; par[y]=x;
Pushup(y); Pushup(x);
}
void Splay(int x,int goal)
{
while(par[x]!=goal)
{
if(par[par[x]]==goal) Rotate(x,ch[par[x]][]==x); //左孩子zig,有孩子zag
else
{
Pushdown(par[par[x]]); Pushdown(par[x]); Pushdown(x);
int y=par[x];
int type=(ch[par[y]][]==y); //type=0,y是右孩子;type=1,y是左孩子
if(ch[y][type]==x)
{
Rotate(x,!type);
Rotate(x,type);
}
else
{
Rotate(y,type);
Rotate(x,type);
}
}
}
if(goal==) root=x;
}
int Get_Kth(int x,int k) //得到第k个节点
{
Pushdown(x);
int t=size[ch[x][]]+;
if(t==k) return x;
if(t>k) return Get_Kth(ch[x][],k);
else return Get_Kth(ch[x][],k-t);
}
int Get_Min(int x)
{
Pushdown(x);
while(ch[x][])
{
x=ch[x][];
Pushdown(x);
}
return x;
}
int Get_Max(int x)
{
Pushdown(x);
while(ch[x][])
{
x=ch[x][];
Pushdown(x);
}
return x;
}
void Build(int &x,int l,int r,int par) //建树,先建立中间结点,再建两端的方法
{
if(l>r) return;
int mid=(l+r)/;
NewNode(x,par,mid);
Build(ch[x][],l,mid-,x);
Build(ch[x][],mid+,r,x);
Pushup(x);
}
void Init() //初始化,前后各加一个空节点
{
root=nodecnt=;
ch[root][]=ch[root][]=size[root]=key[root]=par[root]=rev[root]=;
NewNode(root,,-); //头部加入一个空位
NewNode(ch[root][],root,-); //尾部加入一个空位
Build(Key_value,,n,ch[root][]);
Pushup(ch[root][]);
Pushup(root);
}
void Move(int l,int r,int p) //截取[l,r]放到位置p之后
{
Splay(Get_Kth(root,l-+),); //l的前驱l-1伸展到根
Splay(Get_Kth(root,r++),root); //r的后继r+1伸展到根的右孩子
int tmp=Key_value; //Key_value=ch[ch[root][1]][0]所统领的子树即[l,r]
Key_value=; //剥离[l,r]子树
Pushup(ch[root][]); Pushup(root);
Splay(Get_Kth(root,p++),); //p伸展到根
Splay(Get_Kth(root,p++),root); //p的后继p+1伸展到根的右孩子
Key_value=tmp; par[Key_value]=ch[root][]; //接上[l,r]子树
Pushup(ch[root][]); Pushup(root);
}
void Reverse(int l,int r) //反转[l,r]区间
{
Splay(Get_Kth(root,l-+),);
Splay(Get_Kth(root,r++),root);
Update_Rev(Key_value);
Pushup(ch[root][]);
Pushup(root);
}
/******************************** splay - ed ********************************/ int tot;
void Inorder(int x)
{
if(x==) return;
Pushdown(x);
Inorder(ch[x][]);
tot++;
if(tot>= && tot<=n+)
{
if(tot>) printf(" ");
printf("%d",key[x]);
}
Inorder(ch[x][]);
} int main()
{
scanf("%d%d",&n,&m);
Init(); for(int i=,st,ed;i<=m;i++)
{
scanf("%d%d",&st,&ed); ed=st+ed-; if(i%) Move(st,ed,);
else
{
Reverse(,st-);
Reverse(st,ed);
Reverse(,ed);
}
} Inorder(root);
printf("\n");
}
2018牛客网暑期ACM多校训练营(第三场) H - Shuffle Cards - [splay伸展树][区间移动][区间反转]的更多相关文章
- 2018牛客网暑期ACM多校训练营(第一场)J Different Integers(树状数组)
题意 给出一串数字以及q次查询,每次查询l,r],要求求出[1,l]和[r,n]的所有不相同的数字个数. 分析 先对数组进行倍增,变为两倍长,然后查询就变成一个完整的区间.离线处理,按r从小到大排序, ...
- 2018牛客网暑期ACM多校训练营(第二场)I- car ( 思维)
2018牛客网暑期ACM多校训练营(第二场)I- car 链接:https://ac.nowcoder.com/acm/contest/140/I来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 ...
- 2018牛客网暑期ACM多校训练营(第一场)D图同构,J
链接:https://www.nowcoder.com/acm/contest/139/D来源:牛客网 同构图:假设G=(V,E)和G1=(V1,E1)是两个图,如果存在一个双射m:V→V1,使得对所 ...
- 2018 牛客网暑期ACM多校训练营(第一场) E Removal (DP)
Removal 链接:https://ac.nowcoder.com/acm/contest/139/E来源:牛客网 题目描述 Bobo has a sequence of integers s1, ...
- 2018牛客网暑期ACM多校训练营(第二场)J Farm(树状数组)
题意 n*m的农场有若干种不同种类作物,如果作物接受了不同种类的肥料就会枯萎.现在进行t次施肥,每次对一个矩形区域施某种类的肥料.问最后枯萎的作物是多少. 分析 作者:xseventh链接:https ...
- 2018牛客网暑期ACM多校训练营(第一场)B Symmetric Matrix(思维+数列递推)
题意 给出一个矩阵,矩阵每行的和必须为2,且是一个主对称矩阵.问你大小为n的这样的合法矩阵有多少个. 分析 作者:美食不可负064链接:https://www.nowcoder.com/discuss ...
- 2018牛客网暑期ACM多校训练营(第二场) J - farm - [随机数哈希+二维树状数组]
题目链接:https://www.nowcoder.com/acm/contest/140/J 时间限制:C/C++ 4秒,其他语言8秒 空间限制:C/C++ 262144K,其他语言524288K ...
- 2018牛客网暑期ACM多校训练营(第二场) A - run - [DP]
题目链接:https://www.nowcoder.com/acm/contest/140/A 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262144K ...
- 2018牛客网暑期ACM多校训练营(第一场) D - Two Graphs - [无向图同构]
题目链接:https://www.nowcoder.com/acm/contest/139/D 题目描述 Two undirected simple graphs and where are i ...
- 2018牛客网暑期ACM多校训练营(第一场) J - Different Integers - [莫队算法]
题目链接:https://www.nowcoder.com/acm/contest/139/J 题目描述 Given a sequence of integers a1, a2, ..., an a ...
随机推荐
- getActionBar().setDisplayHomeAsUpEnabled(true)报空指针(已解决)
今天捣鼓了一下午.getActionBar().setDisplayHomeAsUpEnabled(true)总是报空指针.在我的还有一个Android4.4.2的项目中就没有一点问题.我还以为是我自 ...
- 第四章 TCP粘包/拆包问题的解决之道---4.1---
4.1 TCP粘包/拆包 TCP是一个“流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可 ...
- 记安装ubuntu server和一些程序
1. 安装ubuntu server 按照流程走了一遍,一切画面都正常,就是重启后界面只有一个光标闪啊闪,我不知道应该再装一遍还是找老大来解决,想了下,以前电脑就是因为出错才重装的,现在这个情况有可能 ...
- NetBpm 示例:请假审批(6)
转载注明出处: http://www.cnblogs.com/anbylau2130/p/3877983.html 原文: 请假示例 流程定义包源码下载(注:par包就是zip格式压缩包).原文地址: ...
- 使用tinyproxy搭建http代理
一.前言 二.搭建环境 * Linux laptop 2.6.32-45-generic #100-Ubuntu SMP Wed Nov 14 10:41:11 UTC 2012 i686 GNU ...
- U3D各键值说明
KeyCode :KeyCode是由Event.keyCode返回的.这些直接映射到键盘上的物理键. 值 对应键 Backspace 退格键 Delete Delete ...
- delphi调用存储过程
一 . TAdoQuery对象下 1. mysql存储过程 sqls := Format(' call pro_addOneStudent (' + '''%s'',''%s'',''%s'',''% ...
- $ cd `dirname $0` 和PWD用法
在命令行状态下单纯执行 $ cd `dirname $0` 是毫无意义的.因为他返回当前路径的".".这个命令写在脚本文件里才有作用,他返回这个脚本文件放置的目录,并可以根据这 ...
- luanet分布式lua框架
luanet最初只是一个网络框架,它简单的封装了一些网络相关接口然后暴露到lua中,让lua可以构建简单的网络应用. 随着我的手游服务器的开发,我发现在C语言中要实现一个简洁易用的RPC调用接口并不容 ...
- 模型提升方法adaBoost
他通过改变训练样本的权重,学习多个分类器,并将这些分类器进行线性组合,提高分类的性能. adaboost提高那些被前一轮弱分类器错误分类样本的权重,而降低那些被正确分类样本的权重,这样使得,那些没有得 ...