HDU 3487 Play with Chain(Splay)
题目大意
给一个数列,初始时为 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; , INF=0x7fffffff; struct Splay_Tree { struct Node { ]; 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=; ]) T[x].Size+=T[T[x].son[]].Size; ]) T[x].Size+=T[T[x].son[]].Size; } inline void pushDown(int x) { if(!T[x].rev) return; ]) T[T[x].son[]].rev^=; ]) 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]; ]==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); ) root=x; } int Select(int pos, int goal) { int u=root; pushDown(u); ]].Size!=pos) { ]].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) { , ), v=Select(R+, u); ]; 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) { , ), v=Select(R+, u); T[T[v].son[]].rev^=; } void DFS(int u) { pushDown(u); ]) DFS(T[u].son[]); ans.push(T[u].val); ]) DFS(T[u].son[]); } void Display(int n) { while(!ans.empty()) ans.pop(); DFS(root); , x; cnt<n; cnt++, ans.pop()) { for(x=ans.front(); x==-INF; ans.pop(), x=ans.front()); printf("%d", x); ==n) printf("\n"); else printf(" "); } } int build(int L, int R) { ; if(L==R) return L; , 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); ; i<=n+; i++) T[i].init(i-); root=build(, n+); T[].Size=, T[].son[]=root, fa[root]=, fa[]=; } } hehe; int n, m; ]; int main() { // freopen("in", "r", stdin); || m!=-) { hehe.init(n); , a, b, c; i<m; i++) { scanf("%s", 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); } ; }
HDU 3487
题目链接 & AC 通道
HDU 3487 Play with Chain(Splay)的更多相关文章
- 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 ...
- HDU 3478 Play with Chain (Splay树)
这种高级数据结构太难搞了.........现在还是先照着别人的代码敲,做模板..........慢慢花时间来弄懂 #include <iostream> #include <algo ...
- HDU 1890:Robotic Sort(Splay)
http://acm.hdu.edu.cn/showproblem.php?pid=1890 题意:有一个无序序列,经过不断地翻转,使得最后的序列是一个升序的序列,而且如果相同数字要使在原本序列靠前的 ...
- HDU 3487 Play with Chain 【Splay】
1-n的序列,有两种操作: 1,将一段区间翻转 2,将一段区间切下来放到剩余序列的第C个数后 采用延迟更新的方法维护区间的翻转,并维护一个size域. 添加一个最大点和一个最小点,防止出界 翻转时,将 ...
- 【BZOJ3506】排序机械臂(Splay)
[BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标 ...
- 【BZOJ1500】【NOI2005】维修数列(Splay)
[BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...
- HDU 4441 Queue Sequence(splay)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并 ...
- hdu 3487 Play with Chain
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487 YaoYao is fond of playing his chains. He has a c ...
- BZOJ 1251 序列终结者(Splay)
题目大意 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术 ...
随机推荐
- Linux学习笔记(一)
1.正则表达式 \w 匹配任何字类字符,包括下划线.与“[A-Za-z0-9_]”等效. \W 与任何非单词字符匹配.与“[^A-Za-z0-9_]”等效. + 一次或多次匹配前面的字符或子表达 ...
- IOC基础
Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象 ...
- PHP 对象和引用总结
PHP 中使用 简单变量 和 对象 时的区别: ① 很多数据类型都可以写时复制(copy-on-write),例: <?php $a = 'test1'; $b = $a; $b = 'test ...
- JavaScript学习之cookies
使用JavaScript操作cookies 一.什么是cookies? cookies是一种对客户端硬盘的数据进行存取的技术,这种技术能够让网站把少量的数据存储到客户端的硬盘,同时也能够从客户端的硬盘 ...
- Twitter数据抓取
说明:这里分三个系列介绍Twitter数据的非API抓取方法.有兴趣的QQ群交流: BitCrawler网络爬虫QQ群 322937592 1.Twitter数据抓取(一) 2.Twitter数据抓取 ...
- python(二)拾遗
1.int 系统内部自动执行的 a=123>>>>a=int(123)>>>>a=_init_(123) 外部调用 a 2 b=a.bit_length ...
- Leetcode026. Remove Duplicates from Sorted Array
water class Solution { public: int removeDuplicates(vector<int>& nums) { for(vector<int ...
- 【MySQL】MySQL回滚工具
1.mysqlbinlog把事务从binlog中导出 2.从导出的binlog中找到要回滚的事务,去掉第一个DML语句前和最后一个DML语句后与DML无关的binlog信息 3.在目录中新建一个tab ...
- openerp经典收藏 OpenERP库存管理的若干概念讲解(新增库存价值)(转载)
OpenERP库存管理的若干概念讲解(新增库存价值) 原文:http://shine-it.net/index.php/topic,2425.0/topicseen.html 一.复式库存(Doubl ...
- [转]- Winform 用子窗体刷新父窗体,子窗体改变父窗体控件的值
转自:http://heisetoufa.iteye.com/blog/382684 第一种方法: 用委托,Form2和Form3是同一组 Form2 using System; using Sys ...