题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487

YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.
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?

题意:题意比较简单,就给一个数列两种操作:1,CUT a,b,c,在原数列截取区间[a,b](a和b指数列a位置和b位置),然后剩下的数列合并在一起,把截取的区间放在那个数列的c  位置;2,FLIP a b 翻转区间[a,b]。
解法:伸展树+延迟标记。
 ///*hdu 3487*/
///G++ 687ms C++ 609ms
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;
const int maxn=*1e6+;
struct Splay_Tree
{
struct Node
{
Node *ch[],*pre; ///节点的左儿子和右儿子,父亲节点
int value,size; ///节点的值和以此节点为根的子树的节点个数
bool rev; ///判断是否需要翻转
}*root,*null,*lb,*rb,node[maxn];
int count;
bool flag;
Node *NewNode(int value,Node *father)///插入新节点
{
///Node *e=node[++count];这样写不行
Node *e=node+(++count);
e->value=value;
e->size=;
e->pre=father;
e->rev=false;
e->ch[]=e->ch[]=null;
return e;
}
void Update(Node *p)///更新节点p的信息
{
if (p==null) return;
p->size=p->ch[]->size + p->ch[]->size + ;
}
void PushDown(Node *x)///向下更新标记
{
if (x==null) return;
if (x->rev)
{
x->rev=false;
Node *t=x->ch[] ;x->ch[]=x->ch[] ;x->ch[]=t;
x->ch[]->rev= !x->ch[]->rev;
x->ch[]->rev= !x->ch[]->rev;
}
}
void Rotate(Node *x,bool d)///右旋转:true;左旋转:false
{
Node *y=x->pre;
y->ch[!d]=x->ch[d];
if (x->ch[d]!=null) x->ch[d]->pre=y;
x->pre=y->pre;
if (y->pre!=null)
{
if (y==y->pre->ch[d])
y->pre->ch[d]=x;
else y->pre->ch[!d]=x;
}
x->ch[d]=y;
y->pre=x;
Update(y);
Update(x);
if (root==y) root=x;
}
void Splay(Node *x,Node *target)///伸展操作
{
PushDown(x);
Node *y;
while (x->pre!=target)
{
y=x->pre;
if (x==y->ch[])
{
if (y->pre!=target && y->pre->ch[]==y)
Rotate(y,true);
Rotate(x,true);
}
else
{
if (y->pre!=target && y->pre->ch[]==y)
Rotate(y,false);
Rotate(x,false);
}
}
Update(x);
}
void Select(int k,Node *y)///选择第k个位置的节点
{
Node *x=root;
PushDown(x);
while (k!=x->ch[]->size+)
{
if (k<=x->ch[]->size)
x=x->ch[];
else
{
k -= x->ch[]->size+;
x=x->ch[];
}
PushDown(x);
}
Splay(x,y);
}
void MakeTree(int l,int r,int *an,Node *p,int side)
{
if (l>r) return;
int mid=(l+r)>>;
Node *x;
x=NewNode(an[mid],p);
p->ch[side]=x;
MakeTree(l,mid-,an,x,);
MakeTree(mid+,r,an,x,);
Update(x);
}
///****///
///在pos后面插入长度为cnt的区间
void Insert(int pos,int cnt,int *an)
{
Select(pos+,null);
Select(pos+,root);
MakeTree(,cnt,an,root->ch[],);
Splay(root->ch[]->ch[],null);
}
///删除pos后长度为cnt的区间
void Delete(int pos,int cnt,int ind)
{
Node *p1;
Select(pos,null);
Select(pos+cnt+,root);
p1=root->ch[]->ch[];
root->ch[]->ch[]=null; Splay(root->ch[],null);
Select(ind+,null);
Select(ind+,root);
root->ch[]->ch[]=p1;
Splay(root->ch[],null);///注意不是Splay(root->ch[1]->ch[0],null)
}
///旋转pos后长度为cnt的区间
void Reverse(int pos,int cnt)
{
Select(pos,null);
Select(pos+cnt+,root);
root->ch[]->ch[]->rev= !root->ch[]->ch[]->rev;
Splay(root->ch[]->ch[],null);
}
void Index(int pos)
{
Select(pos+,null);
printf("%d",root->value);
}
void Out()///调试程序
{
flag=false;
Print(root);///打印整个区间
printf("\n");
}
void Print(Node *now)///打印区间
{
if (now==null) return;
if (now->ch[]==null&&now->ch[]==null)
{
if (now->value!=inf)
{
if (flag) printf(" ");
flag=true;
printf("%d",now->value);
}
return;
}
PushDown(now);
Print(now->ch[]);
if (now->value!=inf)
{
if (flag) printf(" ");
flag=true;
printf("%d",now->value);
}
Print(now->ch[]);
}
void init()
{
count=-;
null=;
null=NewNode(inf,);
null->size=;
lb=root=NewNode(inf,null);
rb=root->ch[]=NewNode(inf,root);
Update(root);
}
}splay;
int an[maxn];
int main()
{
int n,m; char str[];
int a,b,c;
while (scanf("%d%d",&n,&m)!=EOF)
{
if (n< && m<) break;
splay.init();
for (int i= ;i<=n ;i++) an[i]=i;
splay.Insert(,n,an);
while (m--)
{
scanf("%s",str);
if (str[]=='C')
{
scanf("%d%d%d",&a,&b,&c);
splay.Delete(a,b-a+,c);
}
else
{
scanf("%d%d",&a,&b);
splay.Reverse(a,b-a+);
}
}
splay.Out();
}
return ;
}

hdu 3487 Play with Chain的更多相关文章

  1. HDU 3487 Play with Chain(Splay)

    题目大意 给一个数列,初始时为 1, 2, 3, ..., n,现在有两种共 m 个操作 操作1. CUT a b c 表示把数列中第 a 个到第 b 个从原数列中删除得到一个新数列,并将它添加到新数 ...

  2. HDU 3487 Play with Chain | Splay

    Play with Chain Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  3. HDU 3487 Play with Chain (splay tree)

    Play with Chain Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  4. HDU 3487 Play with Chain 【Splay】

    1-n的序列,有两种操作: 1,将一段区间翻转 2,将一段区间切下来放到剩余序列的第C个数后 采用延迟更新的方法维护区间的翻转,并维护一个size域. 添加一个最大点和一个最小点,防止出界 翻转时,将 ...

  5. Hdu 3487 play the chain

    Description 瑶瑶很喜欢玩项链,她有一根项链上面有很多宝石,宝石从1到n编号. 首先,项链上的宝石的编号组成一个序列:1,2,3,...,n. 她喜欢两种操作: 1.CUT a b c:他会 ...

  6. HDU 3487:Play with Chain(Splay)

    http://acm.hdu.edu.cn/showproblem.php?pid=3487 题意:有两种操作:1.Flip l r ,把 l 到 r 这段区间 reverse.2.Cut a b c ...

  7. 【HDU 3487】Play with Chain Splay

    题意 给定$n$个数序列,每次两个操作,将区间$[L,R]$拼接到去掉区间后的第$c$个数后,或者翻转$[L,R]$ Splay区间操作模板,对于区间提取操作,将$L-1$ Splay到根,再将$R+ ...

  8. Play with Chain 【HDU - 3487】【Splay+TLE讲解】

    题目链接 很好的一道题,用了三天多的时间,终于知道了我为什么T的原因,也知道了在Splay的同时该怎样子的节约时间,因为Splay本身就是大常数的O(N*logN),我们如果不在各种细节上节约时间,很 ...

  9. 【HDU 5233】Tree chain problem (树形DP+树剖+线段树|树状数组)最大权不相交树链集

    [题目] Tree chain problem Problem Description Coco has a tree, whose vertices are conveniently labeled ...

随机推荐

  1. C#中如何将combox中的下拉项和一个枚举中的各项进行绑定

    实现一个combobox,将其各个下拉项与枚举进行绑定 效果图如下: 代码详解如下: 枚举: public enum StoreSite { /// <summary> /// 未知 // ...

  2. kettle教程(1) 简单入门、kettle简单插入与更新。打开kettle

    本文要点:Kettle的建立数据库连接.使用kettle进行简单的全量对比插入更新:kettle会自动对比用户设置的对比字段,若目标表不存在该字段,则新插入该条记录.若存在,则更新.   Kettle ...

  3. 文本处理命令--cut、sort、join

    声明:下面介绍的只是命令的常用选项,如果需要详细了解命令全部细节,需要参考其他的资料. 一.cut cut是一个选取命令,就是将一段数据经过分析,取出我们想要的.一般来说,选取信息通常是针对“行”来进 ...

  4. MySQL下查看用户和建立用户

    启动数据库: [root@server ~]# mysqld_safe & [1] 3289 [root@server ~]# 130913 08:19:58 mysqld_safe Logg ...

  5. Android四大组件一----Activity

    最新面试需要复习一下Android基础. {所谓Activity} 通俗点:app上看到的窗口基本都是Activity Android 程序一般是由多个Activity组成,用户看到的能够交互的窗口通 ...

  6. C++primer 阅读点滴记录(三)

    14章 操作符重载和转换 重载操作符是具有特殊名称的函数:保留字operator后接需要定义的操作符符号. 1.重载的操作符名: + – * / % ^ & | ~ ! , = <  & ...

  7. jquery 点击页面其他地方实现隐藏菜单功能

    1.给页面文档添加一个点击事件函数,在函数内实现隐藏菜单功能. $('html').click(function(){//Hide the menus if visible});//用$(docume ...

  8. 第七章 管理类型(In .net4.5) 之 使用类型

    1. 概述 本章介绍 值类型的装箱拆箱.类型转换 以及 C#4.0新推出的 dynamic 关键字. 2. 主要内容 2.1 装箱和拆箱 2.2 类型转换 有四种方式可以实现类型转换: ① 隐式转换: ...

  9. [php]如何更改wamp默认的mysq空密码?

    最近刚开始学php,爬坑中.上午看了会儿书,下了个源码,把文件部署到www下之后,也导入了sql文件,但是进入之后显示 = =  一开始不知道是什么.后来百度之后发现是mysql的问题,应该是源码中p ...

  10. 简答的理解C语言中的各种类型函数

    1.变参函数 变长参数的函数即参数个数可变.参数类型不定 的函数.最常见的例子是printf函数.scanf函数和高级语言的Format函数.在C/C++中,为了通知编译器函数的参数个数和类型可变(即 ...