【HDU3487】【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.
CUT 3 5 4
FLIP 2 6
-1 -1
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#define LOCAL
const int MAXN = + ;
const int INF = ;
const int SIZE = ;
const int maxnode = 0x7fffffff + ;
using namespace std;
int M;
struct SPLAY{
struct Node{
int val, size;
bool turn;
Node *ch[], *parent; /*Node(){//暂时不要构造函数,节约时间
val = 0;
size = 0;
turn = 0;
parent = ch[0] = ch[1] = NULL;
}*/
int cmp(){
if (parent->ch[] == this) return ;
else return ;
}
//更新
}*root, *nil, _nil, mem[MAXN];
int tot; void pushdown(Node *&t){
if (t == nil) return;
if (t->turn){
Node *p;
p = t->ch[];
t->ch[] = t->ch[];
t->ch[] = p; if (t->ch[] != nil) t->ch[]->turn ^= ;
if (t->ch[] != nil) t->ch[]->turn ^= ;
t->turn = ;
}
}
void update(Node *&t){
t->size = ;
t->size += t->ch[]->size + t->ch[]->size;
}
Node* NEW(int val){
Node *p = &mem[tot++];
p->val = val;
p->size = ;
p->turn = ;
p->parent = p->ch[] = p->ch[] = nil;
return p;
}
void init(){
//哨兵初始化
nil = &_nil;
_nil.val = _nil.size = _nil.turn = ;
_nil.parent = _nil.ch[] = _nil.ch[] = nil; tot = ;
root = NEW(INF);
root->ch[] = NEW(INF);
root->ch[]->parent = root;
}
//1为右旋
/*void Rotate(Node *&t, int d){
Node *p = t->parent;
pushdown(p);
pushdown(t);
pushdown(t->ch[d]);
//t = p->ch[d ^ 1];这句话是废话,真正的一句一处
p->ch[d ^ 1] = t->ch[d];
if (t->ch[d] != nil) t->ch[d]->parent = p;
t->parent = p->parent;
if (p->parent != nil) p->ch[p->cmp()] = t;
t->ch[d] = p;
p->parent = t;
update(p);//注意这里为什么只要updatep是因为旋转是在伸展中使用的,因此t的更新在splay中
if (root == p) root = t;//换根
}*/
void Rotate(Node *t, int d){
Node *p = t->parent;//t的右旋对于p来说也是右旋
t = p->ch[d ^ ];
p->ch[d ^ ] = t->ch[d];
t->ch[d]->parent = p;
t->ch[d] = p;
t->parent = p->parent;
//注意,这里要更新的原因在于t并不是引用
if (t->parent != nil){
if (t->parent->ch[] == p) t->parent->ch[] = t;
else if (t->parent->ch[] == p) t->parent->ch[] = t;
}
p->parent = t;
if (t->parent == nil) root = t;
//不用换回去了...
update(p);
update(t);
//t->update();
}
void splay(Node *x, Node *y){
pushdown(x);
while (x->parent != y){
if (x->parent->parent == y){
Rotate(x, x->cmp() ^ );
break;
}else{
Rotate(x->parent, x->parent->cmp() ^ );
Rotate(x, x->cmp() ^ );
}
update(x);
}
update(x);//最后退出的update不要忘了
if (nil == y) root = x;
}
//找到第k小的数并将其伸展到y
void find(Node *y, int k){
Node *x = root;
while (){
//if (x == nil) break;//注意我已经在init中插入了两个数
pushdown(x);
int tmp = (x->ch[]->size);
if ((tmp + ) == k) break;
if (k <= tmp) x = x->ch[];
else k -= tmp + , x = x->ch[];
}
pushdown(x);
splay(x, y);
}
//在pos位置后面插入一个数val
void Insert(int pos, int val){
find(nil, pos + );
find(root, pos + );//时刻注意已经插入了两个INF
pushdown(root);
pushdown(root->ch[]);
Node *p = NEW(val), *t = root->ch[];
//一定要拆开!!不能放在ch[1]->[0]
p->ch[] = t;
t->parent = p;
root->ch[] = p;
p->parent = root;
splay(p, nil);
}
//剪掉a,b位置的数并接到c位置后面
void Cut(int a, int b, int c){
find(nil, a);
find(root, b + );
pushdown(root);
pushdown(root->ch[]); Node *p = root->ch[]->ch[];
root->ch[]->ch[] = nil;//剪掉
update(root->ch[]);///不要忘了更新
update(root); find(nil, c + );
find(root, c + );
pushdown(root);
pushdown(root->ch[]); root->ch[]->ch[] = p;
p->parent = root->ch[];
update(root->ch[]);
update(root);
splay(p, nil);
}
void Reverse(int l, int r){
find(nil, l);
find(root, r + );
//print(root);
root->ch[]->ch[]->turn ^= ;
Node *p = root->ch[]->ch[];
splay(p, nil);
}
void print(Node *t){
if (t == nil) return;
pushdown(t);
print(t->ch[]);
if (t->val != INF){
if (M != ) {printf("%d ", t->val);M--;}
else printf("%d", t->val);
}
print(t->ch[]);
}
}A;
int n, m; void init(){
A.init();
//scanf("%d%d", &n, &m);
for (int i = ; i < n; i++){
A.Insert(i, i + );
}
//A.print(A.root);
}
void work(){
for (int i = ; i <= m; i++){
char str[];
scanf("%s", str);
if (str[] == 'C'){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
A.Cut(a, b, c);
}else{
int l, r;
scanf("%d%d", &l, &r);
A.Reverse(l, r);
}
//A.print(A.root);
}
M = n;
A.print(A.root);
} int main(){ while (scanf("%d%d", &n, &m)){
if (n == - && m == -) break;
init();
//A.find(A.nil, 3);
//printf("%d", A.root->size);
work();
printf("\n");
}
return ;
}
【HDU3487】【splay分裂合并】Play with Chain的更多相关文章
- bzoj3223 文艺平衡树 (treap or splay分裂+合并)
3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 3313 Solved: 1883 [Submit][S ...
- hdu3487 splay树
Play with Chain Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 【BZOJ-2809】dispatching派遣 Splay + 启发式合并
2809: [Apio2012]dispatching Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2334 Solved: 1192[Submi ...
- 【BZOJ-2733】永无乡 Splay+启发式合并
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2048 Solved: 1078[Submit][Statu ...
- BZOJ2733 永无乡【splay启发式合并】
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...
- bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)
这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...
- 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)
题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被 ...
- 算法复习——splay+启发式合并(bzoj2733-永无乡)
题目: Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通 ...
随机推荐
- 【转】VS 代码行数统计
[转自]http://www.cnblogs.com/JuneZhang/archive/2013/01/10/2854572.html VS用正则表达式统计代码行数 利用VS2010的查找功能和正则 ...
- RAM和DDR
DDR内存现在渐渐成为内存市场中新的宠儿,因其合理的性价比从其诞生以来一直受到人们热烈的期望,希望这一新的内存产品全面提升系统的处理速度和带宽,就连对Rambus抱有无限希望的Intel公司也向外界宣 ...
- hdu 4091 Zombie’s Treasure Chest(数学规律+枚举)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4091 /** 这题的一种思路就是枚举了: 基于这样一个事实:求出lcm = lcm(s1,s2), n ...
- poj 1564 Sum It Up【dfs+去重】
Sum It Up Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6682 Accepted: 3475 Descrip ...
- Cocos2d-x CCActionInterval
第一部分:CCActionInterval家族(持续动作) 持续动作,顾名思义,就是该动作的执行将持续一段时间.因此持续动作的静态生成函数,往往附带一个时间值Duration.例如: CCAction ...
- 我眼中的 Oracle 性能优化
恒生技术之眼 作者 林景忠 大家对于一个业务系统的运行关心有如下几个方面:功能性.稳定性.效率.安全性.而一个系统的性能有包含了网络性能.应用性能.中间件性能.数据库性能等等. 今天从数据库性能的角度 ...
- json字符串、json对象、数组 三者之间的转换
json字符串转化成json对象 // jquery的方法 var jsonObj = $.parseJSON(jsonStr) //js 的方法 var jsonObj = JSON.parse(j ...
- 【Android - MD】之TabLayout的使用
TabLayout是Android 5.0新特性--Material Design中的一个控件,是一个标签页的导航条,常结合ViewPager完成页面导航. 和其他MD控件一样,使用TabLayout ...
- VS2010+Opencv-2.4.9的配置攻略
1.下载软件 vs2010入门书籍,免积分下载 http://download.csdn.net/detail/u014112584/7325617 opencv2.4.0版本号和一些样例,免积分 ...
- 怎样让HTML5调用手机摄像头拍照——实践就是一切
原文:怎样让HTML5调用手机摄像头拍照--实践就是一切 NanShan 小编将思路提供给了大家.学编程最重要的是实践,我这尽管有完好的代码,可是希望大家都能够自己写出属于自己的代码 HTML5 Th ...