POJ 3580 - SuperMemo - [伸展树splay]
题目链接:http://poj.org/problem?id=3580
Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1, A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:
- ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
- REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
- REVOLVE x y T: rotate sub-sequence {Ax ... Ay} T times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
- INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
- DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
- MIN x y: query the participant what is the minimum number in sub-sequence {Ax... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2
To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.
Input
The first line contains n (n ≤ 100000).
The following n lines describe the sequence.
Then follows M (M ≤ 100000), the numbers of operations and queries.
The following M lines describe the operations and queries.
Output
For each "MIN" query, output the correct answer.
Sample Input
5
1
2
3
4
5
2
ADD 2 4 1
MIN 4 5
Sample Output
5
题意:
给出五种操作:
- ADD x y D: 对区间[x,y]全部加上D;
- REVERSE x y: 反转区间[x,y];
- REVOLVE x y T: 将区间[x,y]向右循环平移T次,每次一格,例如 REVOLVE 2 4 2 在{1, 2, 3, 4, 5}操作结果为{1, 3, 4, 2, 5};
- INSERT x P: 在位置x后面插入一个数P;
- DELETE x: 删除位置x上的数;
- MIN x y: 求区间[x,y]中的最小值;
题解:
splay模板题,lazy标记模仿线段树标记区间加上多少,rev标记标记是否需要反转,mini[x]记录节点x统领的整棵子树(包含自己)的key[x]的最小值。
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2e5+;
int n,m;
int a[maxn]; /******************************** splay - st ********************************/
#define Key_value ch[ch[root][1]][0]
int root,nodecnt;
int par[maxn],ch[maxn][];
int key[maxn],mini[maxn],size[maxn];
int lazy[maxn]; //lazy标记
bool rev[maxn]; //反转标记
int pool[maxn],poolsize; //节点回收
void NewNode(int &x,int p,int k)
{
if(poolsize>) x=pool[--poolsize];
else x=++nodecnt;
par[x]=p;
ch[x][]=ch[x][]=;
key[x]=k;
mini[x]=k;
size[x]=;
lazy[x]=;
rev[x]=;
}
void Update_Rev(int x)
{
if(x==) return;
swap(ch[x][],ch[x][]);
rev[x]^=;
}
void Update_Add(int x,int val)
{
if(x==) return;
key[x]+=val;
mini[x]+=val;
lazy[x]+=val;
}
void Pushup(int x)
{
size[x]=size[ch[x][]]+size[ch[x][]]+; mini[x]=key[x];
if(ch[x][]) mini[x]=min(mini[x],mini[ch[x][]]);
if(ch[x][]) mini[x]=min(mini[x],mini[ch[x][]]);
}
void Pushdown(int x)
{
if(rev[x])
{
Update_Rev(ch[x][]);
Update_Rev(ch[x][]);
rev[x]=;
}
if(lazy[x])
{
Update_Add(ch[x][],lazy[x]);
Update_Add(ch[x][],lazy[x]);
lazy[x]=;
}
}
void Inorder(int x) //debug
{
if(x==) return;
Pushdown(x);
Inorder(ch[x][]);
printf("%d ",key[x]);
Inorder(ch[x][]);
Pushup(x);
if(x==root) printf("\n");
}
void Rotate(int x,int type) //旋转,0为左旋zag,1为右旋zig
{
int y=par[x];
Pushdown(y); Pushdown(x); //先把y的标记向下传递,再把x的标记往下传递
ch[y][!type]=ch[x][type]; par[ch[x][type]]=y;
if(par[y]) ch[par[y]][(ch[par[y]][]==y)]=x;
par[x]=par[y];
ch[x][type]=y; par[y]=x;
Pushup(y); Pushup(x);
}
void Splay(int x,int goal)
{
while(par[x]!=goal)
{
if(par[par[x]]==goal) Rotate(x,ch[par[x]][]==x); //左孩子zig,右孩子zag
else
{
Pushdown(par[par[x]]); Pushdown(par[x]); Pushdown(x);
int y=par[x];
int type=(ch[par[y]][]==y); //type=0,y是右孩子;type=1,y是左孩子
if(ch[y][type]==x)
{
Rotate(x,!type);
Rotate(x,type);
}
else
{
Rotate(y,type);
Rotate(x,type);
}
}
}
if(goal==) root=x;
}
int Get_Kth(int x,int k) //得到第k个节点
{
Pushdown(x);
int t=size[ch[x][]]+;
if(t==k) return x;
if(t>k) return Get_Kth(ch[x][],k);
else return Get_Kth(ch[x][],k-t);
}
int Get_Min(int x)
{
Pushdown(x);
while(ch[x][])
{
x=ch[x][];
Pushdown(x);
}
return x;
}
int Get_Max(int x)
{
Pushdown(x);
while(ch[x][])
{
x=ch[x][];
Pushdown(x);
}
return x;
}
void Build(int &x,int l,int r,int par) //建树,先建立中间结点,再建两端的方法
{
if(l>r) return;
int mid=(l+r)/;
NewNode(x,par,a[mid]);
Build(ch[x][],l,mid-,x);
Build(ch[x][],mid+,r,x);
Pushup(x);
}
void Init() //初始化,前后各加一个空节点
{
root=nodecnt=poolsize=;
par[root]=ch[root][]=ch[root][]=;
key[root]=size[root]=;
lazy[root]=rev[root]=;
NewNode(root,,-); //头部加入一个空位
NewNode(ch[root][],root,-); //尾部加入一个空位
Build(Key_value,,n,ch[root][]);
Pushup(ch[root][]);
Pushup(root);
}
void Add(int l,int r,int val)
{
Splay(Get_Kth(root,l-+),); //l的前驱l-1伸展到根
Splay(Get_Kth(root,r++),root); //r的后继r+1伸展到根的右孩子
Update_Add(Key_value,val);
Pushup(ch[root][]);
Pushup(root);
}
void Move(int l,int r,int p) //截取[l,r]放到位置p之后
{
Splay(Get_Kth(root,l-+),); //l的前驱l-1伸展到根
Splay(Get_Kth(root,r++),root); //r的后继r+1伸展到根的右孩子
int tmp=Key_value; //Key_value=ch[ch[root][1]][0]所统领的子树即[l,r]
Key_value=; //剥离[l,r]子树
Pushup(ch[root][]); Pushup(root);
Splay(Get_Kth(root,p++),); //p伸展到根
Splay(Get_Kth(root,p++),root); //p的后继p+1伸展到根的右孩子
Key_value=tmp; par[Key_value]=ch[root][]; //接上[l,r]子树
Pushup(ch[root][]); Pushup(root);
}
void Reverse(int l,int r) //反转[l,r]区间
{
Splay(Get_Kth(root,l-+),);
Splay(Get_Kth(root,r++),root);
Update_Rev(Key_value);
Pushup(ch[root][]);
Pushup(root);
}
void Revolve(int l,int r,int T)
{
int D=r-l+;
int L=T%D;
if(L==) return;
Move(r-L+,r,l-);
}
void Insert(int p,int k)
{
Splay(Get_Kth(root,p++),); //p伸展到根
Splay(Get_Kth(root,p++),root); //p的后继p+1伸展到根的右孩子
Inorder(Key_value);
NewNode(Key_value,ch[root][],k);
Pushup(ch[root][]); Pushup(root);
}
void Collect(int x) //回收节点x统领的子树
{
if(x==) return;
pool[poolsize++]=x;
Collect(ch[x][]);
Collect(ch[x][]);
}
void Delete(int p)
{
Splay(Get_Kth(root,p-+),); //p的前驱p-1伸展到根
Splay(Get_Kth(root,p++),root); //p的后继p+1伸展到根的右孩子
Collect(Key_value);
par[Key_value]=;
Key_value=;
Pushup(ch[root][]); Pushup(root);
}
int Min(int l,int r)
{
Splay(Get_Kth(root,l-+),);
Splay(Get_Kth(root,r++),root);
return mini[Key_value];
}
/******************************** splay - ed ********************************/ int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
Init(); scanf("%d",&m);
char op[];
for(int i=;i<=m;i++)
{
scanf("%s",op);
if(op[]=='A')
{
int x,y,D; scanf("%d%d%d",&x,&y,&D);
Add(x,y,D);
}
if(op[]=='R' && op[]=='E')
{
int x,y; scanf("%d%d",&x,&y);
Reverse(x,y);
}
if(op[]=='R' && op[]=='O')
{
int x,y,T; scanf("%d%d%d",&x,&y,&T);
Revolve(x,y,T);
}
if(op[]=='I')
{
int x,p; scanf("%d%d",&x,&p);
Insert(x,p);
}
if(op[]=='D')
{
int x; scanf("%d",&x);
Delete(x);
}
if(op[]=='M')
{
int x,y; scanf("%d%d",&x,&y);
printf("%d\n",Min(x,y));
}
//Inorder(root);
}
}
两组数据:
5
1 2 3 4 5 11
ADD 1 4 1
REVERSE 2 4
ADD 2 5 2
REVOLVE 2 4 2
DELETE 4
MIN 1 3
REVERSE 1 4
INSERT 2 4
REVOLVE 1 4 6
DELETE 2
MIN 1 4
10
1 2 3 4 5 6 7 8 9 10
15
ADD 4 8 3
MIN 5 7
MIN 7 10
REVERSE 2 5
MIN 2 6
MIN 2 3
INSERT 3 4
MIN 3 4
MIN 5 10
DELETE 6
MIN 3 5
MIN 4 4
REVOLVE 3 6 7
MIN 5 8
MIN 7 10
第一次写完之后一些BUG通过第一组数据调完了,感觉应该没问题了,然后交了发现WA,
然后用第二组数据一测,发现居然是因为用来debug的一些输出忘记删掉了……尴尬……
POJ 3580 - SuperMemo - [伸展树splay]的更多相关文章
- POJ 3580 SuperMemo 伸展树
题意: 维护一个序列,支持如下几种操作: ADD x y D:将区间\([x,y]\)的数加上\(D\) REVERSE x y:翻转区间\([x,y]\) REVOLVE x y T:将区间\([x ...
- 伸展树Splay
新学的,其实吧,就那么回事.... 看了几天,splay处理序列问题,真的非常厉害,翻转,插入,删除,线段树实现不了的功能,splay用起来很方便. POJ 3580 SuperMemo 这题基本就是 ...
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- 纸上谈兵: 伸展树 (splay tree)[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...
- K:伸展树(splay tree)
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...
- 高级搜索树-伸展树(Splay Tree)
目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...
- poj 3580 SuperMemo
题目连接 http://poj.org/problem?id=3580 SuperMemo Description Your friend, Jackson is invited to a TV sh ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
- [Splay伸展树]splay树入门级教程
首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...
随机推荐
- Xcode提交图片出错:Commit failed not under version control (1)
xcode的svn提交图片经常会出问题,这不我又碰到了,记录下: 修改的是xx@2x.png之类的图标,commit的时候报错 The working copy “ios” failed to com ...
- TCP拥塞控制算法纵横谈-Illinois和YeAH
周五晚上.终于下了雨.所以也终于能够乱七八糟多写点松散的东西了... 方法论问题. 这个题目太大以至于内容和题目的关联看起来有失偏颇.只是也无所谓,既然被人以为"没有方法论"而歧视 ...
- MvvmLight学习篇—— Mvvm Light Toolkit for wpf/silverlight系列(导航)
系列一:看的迷迷糊糊的 一.Mvvm Light Toolkit for wpf/silverlight系列之准备工作 二.Mvvm Light Toolkit for wpf/silverlight ...
- 【Python】Linux Acanoda PySpark Spark
1.安装 Acanoda 2.安装 Spark和Scala 3.安装 PySpark 4.将Spark的Python目录拷贝至 Acanoda目录下 5.安装py4j,切换anaconda中bin目 ...
- spring boot配置文件application.propertis
转自http://www.qiyadeng.com/post/spring-boot-application-properties 本文记录Spring Boot application.proper ...
- centos7/nginx/tornado错误异常收集
临时方法 – 设置系统参数 使用命令setenforce 附: setenforce 设置SELinux 成为enforcing模式 setenforce 设置SELinux 成为permissive ...
- myeclipse使用小技巧
1 如何关掉maven自动更新,去掉前面的勾 2 myeclipse中如何设置不校验js
- HTML5实现图片预览功能
两种方式实现 URL FileReader Index.jsp文件 <%@page contentType="text/html" pageEncoding="UT ...
- IOS多线程之线程属性的配置
版权声明:原创作品,谢绝转载!否则将追究法律责任. 设置线程堆栈的大小: 系统为每个你新创建的线程,都会为你的进程空间分配一定的内存作为该线程的堆栈.这里面有我们局部变量声明我们的方法就是一个堆栈 ...
- 【laravel5.6】 Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes
在进行数据迁移时候报错: 特殊字段太长报错, php artisan migrate 现在utf8mb4包括存储emojis支持.如果你运行MySQL v5.7.7或者更高版本,则不需要做任何事情. ...