题目大意:给出1到n的有序数列,现在有两个操作:

1.CUT a b c 把第a到第b个数剪切下来,放到剩下的第c个数的后边。

2.FLIP a b  把第a到第b个数反转。

经过总共m次操作后,求现在的数列。

n,m<300000

分析:典型的splay题。包含的操作即:查找第k大,剪切,插入,反转等操作。

维护size,rev(反转标记)即可。

通过size可以找到第k大,通过rev做懒标记,可以进行反转。

具体说就是,比如要剪切CUT a,b,c,以先把第a-1个节点splay到根的位置,然后把第b+1个节点spaly到根的右儿子的位置,则a到b这一段就刚好是根的右儿子的左子树了,然后把它剪切下来。再把第c节点splay到根的位置,把第c+1个节点splay到根的右儿子的位置,再把刚才剪切的那一段接在根的右儿子的左儿子位置即可。FLIP a b的话,先把第a-1个节点splay到根的位置,把第b+1个节点splay到根的右儿子的位置,然后对根的右儿子的左子树打上懒标记即可。注意:打蓝标记应该是tree[i].rev^=1,而不是tree[i].rev=1。我就是这样wa了一次。

因为splay树的伸展特性,splay树中要增加两个额外的虚拟节点,即头节点和尾节点。初始时把头结点作为根节点,把尾节点作为根的右儿子。有效节点作为根的左儿子的右子树。

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 300505
int tot,root,n,m,a,b,c;
char str[];
struct node
{
int val,fa,sz;
bool rev;
int ch[];
}tree[MAXN];
void newnode(int &r,int father,int val)
{
tot++;
r=tot;
tree[tot].fa=father;
tree[tot].val=val;
}
void build(int &root,int l,int r,int father)
{
if(l>r)return;
int mid=(l+r)/;
newnode(root,father,mid);
build(tree[root].ch[],l,mid-,root);
build(tree[root].ch[],mid+,r,root);
tree[root].sz=tree[tree[root].ch[]].sz+tree[tree[root].ch[]].sz+;
}
void init()
{
tot=root=;
memset(tree,,sizeof tree);
newnode(root,,-);
newnode(tree[root].ch[],root,-);
build(tree[tree[].ch[]].ch[],,n,tree[].ch[]);
tree[tree[].ch[]].sz=tree[tree[tree[].ch[]].ch[]].sz+;
tree[].sz=tree[tree[].ch[]].sz+;
}
void pd(int &r)
{
if(tree[r].rev==)
{swap(tree[r].ch[],tree[r].ch[]);
tree[tree[r].ch[]].rev^=;
tree[tree[r].ch[]].rev^=;
tree[r].rev=;
} }
void pu(int &r)
{
tree[r].sz=tree[tree[r].ch[]].sz+tree[tree[r].ch[]].sz+;
}
void rotato(int &r,bool kind)
{
int y=tree[r].fa;
int yy=tree[y].fa;
if(yy)
{
tree[yy].ch[tree[yy].ch[]==y]=r;
}
tree[r].fa=yy;
tree[tree[r].ch[kind]].fa=y;
tree[y].ch[!kind]=tree[r].ch[kind];
tree[y].fa=r;
tree[r].ch[kind]=y;
pu(y);
pu(r);
}
void splay(int &r,int goal)
{
while(tree[r].fa!=goal)
{
int y=tree[r].fa;
int yy=tree[y].fa;
if(yy==goal)rotato(r,tree[y].ch[]==r);
else
{
int kind=(tree[y].ch[]==r);
if(tree[yy].ch[kind]==y)
{
rotato(r,kind);
rotato(r,!kind);
}
else
{
rotato(y,kind);
rotato(r,kind);
}
}
}
if(goal==)
root=r;
}
int find(int r,int k)
{
pd(r);
if(tree[tree[r].ch[]].sz==k-)
return r;
else if(tree[tree[r].ch[]].sz>k-)
return find(tree[r].ch[],k);
else return find(tree[r].ch[],k-tree[tree[r].ch[]].sz-);
}
void print(int &r)
{
pd(r);
if(tree[r].ch[])
print(tree[r].ch[]);
if(tree[r].val!=-){printf("%d",tree[r].val);if(tot>)printf(" ");tot--;}
if(tree[r].ch[])
print(tree[r].ch[]);
}
int main()
{ while(scanf("%d%d",&n,&m)&&(n>=&&m>=))
{
init();
for(int i=;i<m;i++)
{
scanf("%s",str);
if(str[]=='C')
{
scanf("%d%d%d",&a,&b,&c);
int x1=find(root,a);
int y1=find(root,b+);
splay(x1,);
splay(y1,root);
int t=tree[tree[root].ch[]].ch[];
tree[tree[root].ch[]].ch[]=;
pu(tree[root].ch[]);
pu(root);
x1=find(root,c+);
y1=find(root,c+);
splay(x1,);
splay(y1,root);
tree[tree[root].ch[]].ch[]=t;
tree[t].fa=tree[root].ch[];
pu(tree[root].ch[]);
pu(root);
}
else
{
scanf("%d%d",&a,&b);
int x=find(root,a);
int y=find(root,b+);
splay(x,);
splay(y,root);
tree[tree[tree[root].ch[]].ch[]].rev^=;
}
}
print(root);
printf("\n");
}
}

HDU3487 play with chain的更多相关文章

  1. HDU--3487 Play with Chain (Splay伸展树)

    Play with Chain Problem Description YaoYao is fond of playing his chains. He has a chain containing ...

  2. HDU3487 Play With Chain [Splay]

    题目传送门 题目描述 Problem Description YaoYao is fond of playing his chains. He has a chain containing n dia ...

  3. HDU3487 Play with Chain splay 区间反转

    HDU3487 splay最核心的功能是将平衡树中的节点旋转到他的某个祖先的位置,并且维持平衡树的性质不变. 两个操作(数组实现) cut l,r, c把[l,r]剪下来放到剩下序列中第c个后面的位置 ...

  4. HDU-3487 Play with Chain Splay tee区间反转,移动

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487 对于一个数列有两种操作:1.CUT a b c,先取出a-b区间的数,然后把它们放在取出后的第c ...

  5. 【HDU3487】【splay分裂合并】Play with Chain

    Problem Description YaoYao is fond of playing his chains. He has a chain containing n diamonds on it ...

  6. HDU 3487 Play with Chain | Splay

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

  7. hdu3487 splay树

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

  8. 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 ...

  9. STM32用JLINK 烧写程序时出现NO Cortex-m device found in JTAG chain现象和解决方案

    现象 CPU: STM32107VC 用JLINK 烧写程序时出现NO Cortex-m device found in JTAG chain 如图无法查找到硬件就是CPU 提示1:NO Cortex ...

随机推荐

  1. 初学jquery,自己写的一个jquery幻灯片,代码有些笨拙,希望有大神可以指点一二,精简一下代码

    html代码 <div class="picCon"> <div class="bigPic"> <ul> <li c ...

  2. Ubuntu 安装桌面且远程连接

    前言:  一般服务器是不装桌面的,因为会牺牲很多性能,这里就选择很小桌面,牺牲一定性能  这里就采用x2go, 这里是在ubuntu server 14.04 安装成功,其实它是可用于linux所有  ...

  3. BZOJ2733 [HNOI2012]永无乡

    直接平衡树启发式合并就好了...貌似是个很高端的东西.. 貌似可以证明splay的启发式合并是均摊$O(nlogn)$的...而其他平衡树都不行,所以其他的复杂度都是$O(nlog^2n)的$的 所以 ...

  4. [转]如何让div中的内容垂直居中

    转自:http://blog.163.com/yan_1990/blog/static/197805107201211311515454/ 虽然Div布局已经基本上取代了表格布局,但表格布局和Div布 ...

  5. CentOS Mysql 5.1.73 主从配置

    ---------------------------------------------- 1 修改my.cnf ------------------------------------------ ...

  6. iptables基本规则

    注意:iptables只能被拥有超级权限的用户设置.   重启 清空 iptables 规则:在终端输入:   iptables -F iptables -X iptables -t nat -F i ...

  7. android baseActivity

    package newdemo.jeno.designdemo.activitynew; import android.os.Bundle;import android.support.annotat ...

  8. UISegmentedControl的详细使用

    当用户输入不仅仅是布尔值时,可使用分段控件(UISegmentedControl).分段控件提供一栏按钮(有时称为按钮栏),但只能激活其中一个按钮.分段控件会导致用户在屏幕上看到的内容发生变化.它们常 ...

  9. FileWriter和FileReader简单使用

    FileWriter和FileReader使用 package com.main.test; import java.io.FileNotFoundException; import java.io. ...

  10. 黑马程序员——【Java高新技术】——JDK1.5新特性:静态导入、可变参数、增强型for循环、自动装箱拆箱、枚举

    ---------- android培训.java培训.期待与您交流! ---------- 一.静态导入 1.import和import static区别: (1)import 是导入一个类或某个包 ...