【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 来表示.某些岛之间由巨大的桥连接,通 ...
随机推荐
- Rails 看起来很不错哦。
最新在工作中遇上了ruby,确切的说是rails. 其实我的工作是一个渗透测试工程师(其实就是拿着一堆黑客工具扫描的活). 而我不怎么了解ruby on rails.但是客户即将上线的商城系统是用 ...
- [PHP] 跳转以及回到原来的地址
回到原来的地址: 1.PHP(PHP代码) Header('Location:'.$_SERVER["HTTP_REFERER"]); 2.JavaScript(相当于后退按钮,- ...
- Android NDK开发指南---Application.mk文件和android.mk文件
https://android.googlesource.com/platform/development/+/donut-release/ndk/docs/OVERVIEW.TXT https:// ...
- Tomcat8 配置NIO
conf/server.xml 打开:<Executor name="tomcatThreadPool" namePrefix="catalina-exec-&qu ...
- Hibernate环境搭建超详细
前言 环境搭建其实可以简单到导入相关jar包即可. 但是对于学习来说,这个环境搭建的内容还是挺多的,目的是提供一个让我们如何快速学习和掌握类库的学习环境.作为程序猿,学习和使用类库是必须掌握的技能.如 ...
- Codeforces Beta Round #51 D. Beautiful numbers
D. Beautiful numbers time limit per test 4 seconds memory limit per test 256 megabytes input standar ...
- git 工具
https://www.kernel.org/pub/software/scm/git/ wget https://www.kernel.org/pub/software/scm/git/git-2. ...
- iOS View的Frame和bounds之区别,setbounds使用(深入探究)
前言: 在ios开发中经常遇到两个词Frame和bounds,本文主要阐述Frame和bound的区别,尤其是bound很绕,较难理解. 一.首先,看一下公认的资料: 先看到下面的代码你肯定就明白了一 ...
- Map的迭代操作
Map的迭代操作 public static void main(String[] args) { Map<String, List<Integer>> map = new H ...
- Java设计模式01:设计模式的 分类 和 设计原则
一.总体来说设计模式分为三大类: 创建型模式:对象的创建. 创建对象本身是比较耗时的操作,所以我们这里专门找人来帮我们创建对象,我们根据经验总结出来的设计成熟的思路模式. 结构型模式:对象的组成(结构 ...