HDU 3487 Play with Chain(Splay)

时间:2022-09-05 16:16:47

题目大意

给一个数列,初始时为 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&rpar;

    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】&lbrack;ZJOI2006&rsqb;游戏排名系统 (Splay)

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

  9. 【BZOJ1056】&lbrack;HAOI2008&rsqb;排名系统(Splay)

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

随机推荐

  1. Windows 7 性能优化

    1."计算机" 2.右键>"属性" 3."高级系统设置">"高级" 4."性能"> ...

  2. 黄聪:jquery 校验中国身份证号码

    大陆18位身份证(第二代身份证) 身份号码是一组具有特征组合码,由十七位数字本体码和一位校验码组成. 排列顺序从左至右依次为:六位数字地区码,八位数字生日码,三位数字顺序码和一位数字校验码. 校验方法 ...

  3. (转)Sublime Text 2 2&period;0&period;2 序列号

    ----- BEGIN LICENSE -----Andrew WeberSingle User LicenseEA7E-855605813A03DD 5E4AD9E6 6C0EEB94 BC9979 ...

  4. ubuntu下打开终端插件

    一个 nautilus 插件,用于在任意目录中打开终端 nautilus-open-terminal

  5. linux c截断文件

    http://www.cnblogs.com/zhuxiongfeng/archive/2010/08/24/1807505.html

  6. mysql 5&period;6 oom 图

  7. 在Eclipse的DDMS中查看手机data文件夹中的内容

    在模拟器状态下,在Eclipse的DDMS中的File Explorer下查看手机data/data中的内容是件非常轻松的事情,特别是查看databases 但是在真机模式下就全然不是那么一回事了,在 ...

  8. 第一个shell编程,输出hello world!

    在计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器).它类似于DOS下的command和后来的cmd.exe.它接收用户命令,然后调用相应的应用程序.--- ...

  9. &lbrack;国嵌攻略&rsqb;&lbrack;044&rsqb;&lbrack;初始化Bss段&rsqb;

    BSS段的作用 1.变量存储的空间 初始化的全局变量:数据段 未初始化的全局变量:BSS段 局部变量:栈 动态分配变量:堆 2.为什么要对BSS段初始化 未初始化的全局变量在使用时才被赋值,未了避免在 ...

  10. IO综合练习--文件切割和文件合并

    有时候一个视频文件或系统文件太大了,上传和下载可能会受到限制,这时可以用文件切割器把文件按大小切分为文件碎片, 等到要使用这个文件了,再把文件碎片合并成原来的文件即可.下面的代码实现了文件切割和文件合 ...