HDU--3487 Play with Chain (Splay伸展树)
Play with Chain
At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.
He will perform two types of operations:
CUT a b c: He will first cut down the chain from the ath diamond to the bth diamond. And then insert it after the cth diamond on the remaining chain.
For example, if n=8, the chain is: 1 2 3 4 5 6 7 8; We perform “CUT 3 5 4”, Then we first cut down 3 4 5, and the remaining chain would be: 1 2 6 7 8. Then we insert “3 4 5” into the chain before 5th diamond, the chain turns out to be: 1 2 6 7 3 4 5 8.
FLIP a b: We first cut down the chain from the ath diamond to the bth diamond. Then reverse the chain and put them back to the original position.
For example, if we perform “FLIP 2 6” on the chain: 1 2 6 7 3 4 5 8. The chain will turn out to be: 1 4 3 7 6 2 5 8
He wants to know what the chain looks like after perform m operations. Could you help him?
For each test case, the first line contains two numbers: n and m (1≤n, m≤3*100000), indicating the total number of diamonds on the chain and the number of operations respectively.
Then m lines follow, each line contains one operation. The command is like this:
CUT a b c // Means a CUT operation, 1 ≤ a ≤ b ≤ n, 0≤ c ≤ n-(b-a+1).
FLIP a b // Means a FLIP operation, 1 ≤ a < b ≤ n.
The input ends up with two negative numbers, which should not be processed as a case.
-1 -1
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn = 3e5+;
int siz[maxn],pre[maxn],ch[maxn][],rev[maxn],key[maxn];
int tot,root,n,m;
void NewNode(int &r,int father,int k)
{
r = ++tot;
pre[r] = father;
ch[r][] = ch[r][] = ;
key[r] = k;
siz[r] = ;
rev[r] = ;
}
void update_rev(int r)
{
if (!r)
return ;
swap(ch[r][],ch[r][]);
rev[r] ^= ;
}
void push_up(int r)
{
siz[r] = siz[ch[r][]] + siz[ch[r][]] + ;
}
void push_down(int r)
{
if (rev[r])
{
update_rev(ch[r][]);
update_rev(ch[r][]);
rev[r] = ;
}
}
void build(int &x,int l,int r,int father)
{
if (l > r)
return;
int mid = (l + r) >> ;
NewNode(x,father,mid);
build(ch[x][],l,mid-,x);
build(ch[x][],mid+,r,x);
push_up(x);
}
void init()
{
root = tot = ;
NewNode(root,,-);
NewNode(ch[root][],root,-);
build(ch[ch[root][]][],,n,ch[root][]);
push_up(ch[root][]);
push_up(root);
} void Rotate(int x,int kind)
{
int y = pre[x];
push_down(y);
push_down(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if (pre[y])
ch[pre[y]][ch[pre[y]][] == y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
push_up(y);
} void Splay(int r,int goal)
{
push_down(r);
while (pre[r] != goal)
{
if (pre[pre[r]] == goal)
{
push_down(pre[r]);
push_down(r);
Rotate(r,ch[pre[r]][] == r);
}
else
{
int y = pre[r];
int kind = (ch[pre[y]][] == y);
push_down(pre[y]);
push_down(y);
push_down(r);
if (ch[y][kind] == r)
{
Rotate(y,!kind);
Rotate(r,!kind);
}
else
{
Rotate(r,kind);
Rotate(r,!kind);
}
}
}
push_up(r);
if (goal == )
root = r;
}
int Get_kth(int r,int k)
{
push_down(r);
int t = siz[ch[r][]] + ;
if (k == t)
return r;
if (k >= t)
return Get_kth(ch[r][],k-t);
else
return Get_kth(ch[r][],k);
}
void Reverse(int u,int v)
{
if (u > v)
return;
Splay(Get_kth(root,u),);
Splay(Get_kth(root,v+),root);
update_rev(ch[ch[root][]][]);
push_up(ch[root][]);
push_up(root);
}
void cut(int x,int y,int z) // cut函数本来想着用几次翻转来实现,推了半天没有推出来。so借鉴kuangbin巨巨的做法
{
Splay(Get_kth(root,x),);
Splay(Get_kth(root,y+),root);
int tmp = ch[ch[root][]][];
ch[ch[root][]][] = ;
push_up(ch[root][]);
push_up(root);
Splay(Get_kth(root,z+),);
Splay(Get_kth(root,z+),root);
ch[ch[root][]][] = tmp;
pre[ch[ch[root][]][]] = ch[root][];
push_up(ch[root][]);
push_up(root);
}
bool flag;
void dfs(int r)
{
if (!r)
return;
push_down(r);
dfs(ch[r][]);
if (r != - && key[r] != -)
{
printf(flag ? " %d":"%d",key[r]);
flag = ;
}
dfs(ch[r][]);
}
int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
while (~scanf ("%d%d",&n,&m))
{
if (n < && m < )
break;
init();
for (int i = ; i < m; i++)
{
char op[];
int x,y,z;
scanf ("%s",op);
if (op[] == 'C')
{
scanf ("%d%d%d",&x,&y,&z);
cut(x,y,z);
}
else
{
scanf ("%d%d",&x,&y);
Reverse(x,y);
}
}
flag = ;
dfs(root);
printf("\n");
}
return ;
}
HDU--3487 Play with Chain (Splay伸展树)的更多相关文章
- HDU 3487 Play with Chain | Splay
Play with Chain Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- HDU 3487 Play with Chain(Splay)
题目大意 给一个数列,初始时为 1, 2, 3, ..., n,现在有两种共 m 个操作 操作1. CUT a b c 表示把数列中第 a 个到第 b 个从原数列中删除得到一个新数列,并将它添加到新数 ...
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- 【学时总结】◆学时·VI◆ SPLAY伸展树
◆学时·VI◆ SPLAY伸展树 平衡树之多,学之不尽也…… ◇算法概述 二叉排序树的一种,自动平衡,由 Tarjan 提出并实现.得名于特有的 Splay 操作. Splay操作:将节点u通过单旋. ...
- hdu 3487 Play with Chain
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487 YaoYao is fond of playing his chains. He has a c ...
- Splay 伸展树
废话不说,有篇论文可供参考:杨思雨:<伸展树的基本操作与应用> Splay的好处可以快速分裂和合并. ===============================14.07.26更新== ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
- Splay伸展树入门(单点操作,区间维护)附例题模板
Pps:终于学会了伸展树的区间操作,做一个完整的总结,总结一下自己的伸展树的单点操作和区间维护,顺便给未来的自己总结复习用. splay是一种平衡树,[平均]操作复杂度O(nlogn).首先平衡树先是 ...
- Codeforces 675D Tree Construction Splay伸展树
链接:https://codeforces.com/problemset/problem/675/D 题意: 给一个二叉搜索树,一开始为空,不断插入数字,每次插入之后,询问他的父亲节点的权值 题解: ...
随机推荐
- linux ubuntu 浏览器 字 字体 虚 解决办法
在刚装好的ubuntu上什么都好,只是浏览器字体很虚,就连百度都虚 解决办法很简单 安装雅黑字体 修改font conf sudo vi /etc/fonts/conf.avail/69-langua ...
- Myeclipse 中添加mysql的jdbc驱动
打开myeclipse后单击菜单栏中的myeclipse——>preferences 然后在Myeclipse Enterprise workbench下的Java Enterprise Pro ...
- mybatis与spring的整合
今天是mybatis的最后一天,也是最为重要的一天,mybatis与spring整合,(spring相关知识我会抽一个大的模块进行讲解). 首先加入Spring的依赖 <dependency&g ...
- Maven初识
说说maven,我们每做一个项目,都要往lib目录扔很多jar包,spring的啊hibernate的啊apache的啊等等,这样就会导致很多包不知从哪个角落下载回来的,名称千奇百怪,版本也不明,项目 ...
- python 下的数据结构与算法---5:递归(Recursion)
定义:递归就是不断分割整体成部分直到可以轻易解决分割出来的部分. 递归表达式三定律: 1:递归表达式必须有个最小单元 (最小单元既是停止递归调用以及能够直接运算的) 2:递归表达式在运算过程中 ...
- Hyper-v虚拟机上网
Windows 8中内置的Hyper-V管理器可以说给许多人带来了惊喜!在Hyper-V管理器强大的同时,也同样面临着设置中一些不可避免的麻烦.有人说,Hyper-V虚拟机联网麻烦,其实,只要掌握了技 ...
- SQL Server 中创建数据库、更改主文件组示例
以下示例在 SQL Server 实例上创建了一个数据库.该数据库包括一个主数据文件.一个用户定义文件组和一个日志文件.主数据文件在主文件组中,而用户定义文件组包含两个次要数据文件.ALTER DAT ...
- c - 对数组进行排序(通过指针的指针)
通过指针的指针,以及一个指针数组,对实际数组元素进行排序,有一个优点,就是排序过程交换的只有指针数组中的值,而不是实际的数组的元素.当实际元素中的对象很大,特别是结构体等类型时,这样做是很有好处. 下 ...
- Action<T> 和 Func<T> 委托
概述: 除了为每个参数和返回类型定义一个新委托类型之外,可以使用Action<T> 和 Func<T> 委托. Action<T> Action<T>委 ...
- Swift中构造器的继承和重写
import Foundation /* 构造器的继承: Swift的子类不会自动继承父类的构造器, 若继承, 则满足如下规则: 1.如果子类没有提供任何指定构造器, 那么它将自动继承父类的所有指定构 ...