题目大意

给一个数列,初始时为 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. JSLint JavaScript代码质量审查工具汉化中文版隆重发布

    JSLint是一款JavaScript代码质量审查工具,它可以指出代码中错误.不规范的地方,非常之严格,甚至多写一个空格都会发出警告. JSLint的审查规则,根据众多前辈多年编程经验而写,字字珠玑, ...

  2. lucene join解决父子关系索引

    http://www.cnblogs.com/LBSer/p/4417074.html 1 背景 以商家(Poi)维度来展示各种服务(比如团购(deal).直连)正变得越来越流行(图1a), 比如目前 ...

  3. Qt for Android 打包 SQLite 数据库

    Qt for Android 调用 SQLite 数据库时, 怎样将已经存在的数据库附加到 APK 中? 直接在你项目里面的Android源码的根目录下新建一个文件夹assets, 数据库就可以放里面 ...

  4. Node.js的颠覆者:PHP的Swoole扩展

          最近2年Node.js很火,异步与协程是网络开发方面热门的话题.在追求新技术的同时,也应该反思下这里面存在的陷阱.Node.js确实是一门有趣好玩有个性的语言和技术,动态性,全异步回调的方 ...

  5. CGI综述

    参考: 详说fastcgi,php-fpm的区别:http://segmentfault.com/q/1010000000256516 什么是CGI.FastCGI.PHP-CGI.PHP-FPM.S ...

  6. 【转】iOS 10 UserNotifications 使用说明

    注意:XCode8的需要手动开启主target Capabilities中的Push Notification. 关于创建多个target后真机测试的证书问题,除了主target手动创建开发和发布证书 ...

  7. fine-uploader 5.11.8 (最新版) 使用感受

    以前测试和使用过 3.X 因为够用,所以一直没升级,今天闲来无聊测试了一下最新版.和3.X比性能上好了很多,但不支持了移动设备的多文件上传. 关于3.X版 可以看这里:http://www.cnblo ...

  8. 查看Exchange邮件队列(queue)

    #加载Exchange管理模块 Add-PSSnapin Microsoft.Exchange.Management.PowerShell.snapin get-queue #查看队列 get-mes ...

  9. Idea的live template参数中的预定义功能

    Predefined Functions to Use in Live Template Variables Item Description annotated("annotation q ...

  10. java list中的对象去重原理

    /******************************************************************************* * * Copyright (c) W ...