题目大意

给一个数列,初始时为 1, 2, 3, ..., n,现在有两种共 m 个操作

  操作1. CUT a b c 表示把数列中第 a 个到第 b 个从原数列中删除得到一个新数列,并将它添加到新数列中第 c 个数的后面

  操作2. FLIP a b 表示把数列中第 a 个数到第 b 个数翻转

经过 m 个操作之后,输出这个数列

1≤n, m≤3*100000

做法分析

这题也不好用线段树做,用 Splay 很快就搞出来了

对于"操作1. CUT a b c" ,只需要将 a-1 旋转到根,b+1旋转成 a-1 的子树,那么 [a, b] 之间的树变成了 b+1 的左子树,将整个子树从原树中删去,并把 b+1 旋转到根。之后把 c 旋转到根,c+1 旋转成 c 的子树,再把刚才删掉的子树添加到 c+1 的左子树上(没添加之前,c+1 的左子树必然为空)

对于“操作2. FLIP a b”,只需要给树中每个节点一个 rev 标记表示是否需要翻转以该节点为根的子树中序遍历所得的数列,和线段树差不多的使用懒操作就行了

还是那些细节问题,在什么时候 pushDown,什么时候 pushUp,写代码的时候一定要想清楚

参考代码

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <queue> using namespace std; const int N=, INF=0x7fffffff; struct Splay_Tree {
struct Node {
int val, Size, son[];
bool rev;
inline void init(int _val) {
val=_val, Size=;
son[]=son[]=rev=;
}
} T[N];
int fa[N], root;
queue <int> ans; inline void pushUp(int x) {
T[x].Size=;
if(T[x].son[]) T[x].Size+=T[T[x].son[]].Size;
if(T[x].son[]) T[x].Size+=T[T[x].son[]].Size;
} inline void pushDown(int x) {
if(!T[x].rev) return;
if(T[x].son[]) T[T[x].son[]].rev^=;
if(T[x].son[]) T[T[x].son[]].rev^=;
swap(T[x].son[], T[x].son[]);
T[x].rev=;
} void Rotate(int x, int kind) {
int y=fa[x], z=fa[y];
pushDown(y), pushDown(x);
T[y].son[!kind]=T[x].son[kind], fa[T[x].son[kind]]=y;
T[x].son[kind]=y, fa[y]=x;
T[z].son[T[z].son[]==y]=x, fa[x]=z;
pushUp(y);
} void Splay(int x, int goal) {
if(x==goal) return;
while(fa[x]!=goal) {
int y=fa[x], z=fa[y];
int rx=T[y].son[]==x, ry=T[z].son[]==y;
if(z==goal) Rotate(x, rx);
else {
if(rx==ry) Rotate(y, ry);
else Rotate(x, rx);
Rotate(x, ry);
}
}
pushUp(x);
if(goal==) root=x;
} int Select(int pos, int goal) {
int u=root;
pushDown(u);
while(T[T[u].son[]].Size!=pos) {
if(T[T[u].son[]].Size>pos) u=T[u].son[];
else {
pos-=T[T[u].son[]].Size+;
u=T[u].son[];
}
pushDown(u);
}
Splay(u, goal);
return u;
} void Cut(int L, int R, int pos) {
int u=Select(L-, ), v=Select(R+, u);
int x=T[v].son[];
fa[x]=, T[v].son[]=;
Splay(v, );
u=Select(pos, ), v=Select(pos+, u);
T[v].son[]=x, fa[x]=v;
Splay(x, );
} void Reverse(int L, int R) {
int u=Select(L-, ), v=Select(R+, u);
T[T[v].son[]].rev^=;
} void DFS(int u) {
pushDown(u);
if(T[u].son[]) DFS(T[u].son[]);
ans.push(T[u].val);
if(T[u].son[]) DFS(T[u].son[]);
} void Display(int n) {
while(!ans.empty()) ans.pop();
DFS(root);
for(int cnt=, x; cnt<n; cnt++, ans.pop()) {
for(x=ans.front(); x==-INF; ans.pop(), x=ans.front());
printf("%d", x);
if(cnt+==n) printf("\n");
else printf(" ");
}
} int build(int L, int R) {
if(L>R) return ;
if(L==R) return L;
int mid=(L+R)>>, sL, sR;
T[mid].son[]=sL=build(L, mid-);
T[mid].son[]=sR=build(mid+, R);
fa[sL]=fa[sR]=mid;
pushUp(mid);
return mid;
} void init(int n) {
T[].init(-INF), T[].init(-INF), T[n+].init(-INF);
for(int i=; i<=n+; i++) T[i].init(i-);
root=build(, n+);
T[].Size=, T[].son[]=root, fa[root]=, fa[]=;
}
} hehe;
int n, m;
char cmd[]; int main() {
// freopen("in", "r", stdin);
while(scanf("%d%d",&n, &m), n!=- || m!=-) {
hehe.init(n);
for(int i=, a, b, c; i<m; i++) {
scanf("%s", cmd);
if(cmd[]=='C') {
scanf("%d%d%d", &a, &b, &c);
hehe.Cut(a, b, c);
}
else {
scanf("%d%d", &a, &b);
hehe.Reverse(a, b);
}
}
hehe.Display(n);
}
return ;
}

HDU 3487

题目链接 & AC 通道

HDU 3487 Play with Chain

HDU 3487 Play with Chain(Splay)的更多相关文章

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

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

  3. HDU 3478 Play with Chain (Splay树)

    这种高级数据结构太难搞了.........现在还是先照着别人的代码敲,做模板..........慢慢花时间来弄懂 #include <iostream> #include <algo ...

  4. HDU 1890:Robotic Sort(Splay)

    http://acm.hdu.edu.cn/showproblem.php?pid=1890 题意:有一个无序序列,经过不断地翻转,使得最后的序列是一个升序的序列,而且如果相同数字要使在原本序列靠前的 ...

  5. HDU 3487 Play with Chain 【Splay】

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

  6. 【BZOJ3506】排序机械臂(Splay)

    [BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标 ...

  7. 【BZOJ1500】【NOI2005】维修数列(Splay)

    [BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...

  8. 【BZOJ1862】[ZJOI2006]游戏排名系统 (Splay)

    [BZOJ1862][ZJOI2006]游戏排名系统 (Splay) 题面 BZOJ 洛谷 题解 双倍经验题

  9. 【BZOJ1056】[HAOI2008]排名系统(Splay)

    [BZOJ1056][HAOI2008]排名系统(Splay) 题面 BZOJ 洛谷 题解 \(Splay\)随便维护一下就好了,至于名字什么的,我懒得手写哈希表了,直接哈希之后拿\(map\)压. ...

随机推荐

  1. jenkins2 multibranch

    通过multibranch类型的pipeline job使得对于多个branch的支持更加简单.只需要创建一个multibranch job,jenkins将自动地为所有的branch创建job. 文 ...

  2. android相关技能

    深读: 如:View.ViewGroup.AdapterView.ListView.GridView.Window.ViewDragHelper.ItemTouchHelper.SurfaceView ...

  3. 【原】对频率论(Frequentist)方法和贝叶斯方法(Bayesian Methods)的一个总结

    注: 本文是对<IPython Interactive Computing and Visualization Cookbook>一书中第七章[Introduction to statis ...

  4. paip.重装系统后firefox火狐收藏夹的恢复

    paip.重装系统后firefox火狐收藏夹的恢复 1.使用procmon跟踪ff保存收藏时候的读写文件.. D:\Users\attilax\AppData\Roaming\Mozilla\Fire ...

  5. PHP基础(一)

    <?php $expression = false; if($expression == true): ?> <p>This will show if the expressi ...

  6. INSERT INTO .. ON DUPLICATE KEY更新多行记录

    现在问题来了,如果INSERT多行记录, ON DUPLICATE KEY UPDATE后面字段的值怎么指定?要知道一条INSERT语句中只能有一个ON DUPLICATE KEY UPDATE,到底 ...

  7. 如何管理和记录 SSIS 各个 Task 的开始执行时间和结束时间以及 Task 中添加|删除|修改的记录数

    开篇语 在这篇日志中 如何在 ETL 项目中统一管理上百个 SSIS 包的日志和包配置框架 我介绍到了包级别的日志管理框架,那么这个主要是针对包这一个层级的 Log 信息,包括包开始执行和结束时间,以 ...

  8. 用ColorMatrix將Bitmap轉成灰度图

    在Android中,若想將整張圖片轉成灰階效果其實有更簡便的方式,只要透過ColorMatrix類別的setSaturation函式將飽和度設為0即可.(您也可以試試從0~1之間的值,看看不同飽和度的 ...

  9. NoteExpress 自定义参考文献输出样式

    最近在写硕士论文,样式中没有符合要求的,于是就自己来编辑下样式文件,下文是网上搜集的关于自定义参考文献的一篇教程,可以参考. 一.分隔符|和连接符*的使用 (1)连接符 * 主要作用是“建立依赖关系” ...

  10. Adafruit的树莓派教程第五课:使用控制电缆

    Adafruit的树莓派教程第五课:使用控制电缆 时间 2014-05-09 01:11:20 极客范 原文 http://www.geekfan.net/9095/ 主题 Raspberry PiM ...