POJ 3580 (伸展树)
题目链接: http://poj.org/problem?id=3580
题目大意:对一个序列进行以下六种操作。输出MIN操作的结果。
解题思路:
六个操作,完美诠释了伸展树有多么吊。注意,默认使用Lazy标记,在pushdown中维护。
ADD操作:为x~y元素加一个d值。首先用split切出x~y元素。然后改变给切出的root->add,root->min,root->v。再merge进原序列。
REVERSE操作:把x~y元素反转。首先用split切出x~y元素,然后改变root->flip标记。再merge进原序列。
REVOLVE操作:把x~y元素偏移T位。注意T可以为负。负向左,正向右。
首先对T进行修正。T=(T%(r-l+1)+(r-l+1))%(r-l+1)),参考自cxlove大神,这样正负方向就一致了,而且解决了没必要的偏移。
这样问题就转化为把[x,y]序列变成left+[y-T+1,y]+[x,y-T]+right,同样参考自cxlove大神。
那么只要split出[x,y-T]就行了。注意T=0时要特判,不然等于切了个0空间,程序就爆了。
INSERT操作:在第x元素后插入P。首先切出[1,x],然后merge这个新的P元素,再merge右段。
注意一下,虽然伸展树是意义上的BST,但是伸展树一旦为了维护原有序列顺序,则可以不再遵循BST的左<=中<=右原则。
这里的INSERT就是,把P元素merge到右边是防止BST维护改变顺序(merge只对left进行BST维护)。
DELETE操作:切出左右两段,merge即可。
MIN操作:求x~y元素最小值。依赖于pushup(也就是maintain),每次变动都要维护root-v,root->left,root->right三部分的最小值。
首先切出[x,y],root->minn就是结果。
额外吐槽一下build操作,首先在0号位置加一个inf大的前置结点,这样就可以split出[x,y]这个段了,如果没有前置结点,则应该这么切[1,x-1],当x=1时就完蛋了。
build(0,n)。这样0号点就被放在了最左边。build的时候为了保持原序列顺序,根据位置进行二分build。在最初把伸展树的高度给压下去。
因为伸展树的平衡性能实在太差,如果build成链,那么就要完蛋啦。
#include "cstdio"
#include "cstdlib"
#include "time.h"
#include "queue"
#include "vector"
#include "cstring"
using namespace std;
struct node
{
node *ch[];
long long v,s,minn,flip,add;
node() {s=flip=add=;minn=<<;}
void maintain()
{
s=;
s+=ch[]->s;
s+=ch[]->s;
minn=min(v,min(ch[]->minn,ch[]->minn));
}
void push_down()
{
if(flip)
{
flip = ;
swap(ch[], ch[]);
ch[]->flip = !ch[]->flip;
ch[]->flip = !ch[]->flip;
}
if(add)
{
ch[]->add+=add;ch[]->add+=add;
ch[]->v+=add;ch[]->v+=add;
ch[]->minn+=add;ch[]->minn+=add;
add=;
}
}
int cmp(int x)
{
int d = x-ch[]->s;
if(d == ) return -;
return d <= ? : ;
}
};
node *null=new node();
node *root;
node *left,*mid,*right,*oo;
vector<int> ans;
long long arr[];
void rotate(node* &o,int d)
{
node *k=o->ch[d^];o->ch[d^]=k->ch[d];k->ch[d]=o;
o->maintain();k->maintain();
o=k;
}
void splay(node* &o,int k)
{
o->push_down();
int d=o->cmp(k);
if(d==) k-=o->ch[]->s+;
if(d!=-)
{
node *p=o->ch[d];
p->push_down();
int d2=p->cmp(k);
if(d2!=-)
{
int k2=(d2==?k:k-p->ch[]->s-);
splay(p->ch[d2],k2);
if(d==d2) rotate(o,d^);else rotate(o->ch[d],d);
}
rotate(o,d^);
}
}
node *merge(node* left,node *right)
{
splay(left,left->s);
left->ch[]=right;
left->maintain();
return left;
}
void split(node *o, int k, node *&left, node *&right)
{
splay(o, k);
left = o;
right = o->ch[];
o->ch[] = null;
left->maintain();
}
void build(int l,int r,node* &o)
{
if(l>r) return;
int mid=(l+r)>>;
o=new node;o->v=arr[mid];o->minn=arr[mid];o->s=;o->ch[]=o->ch[]=null;
build(l,mid-,o->ch[]);
build(mid+,r,o->ch[]);
o->maintain();
}
void INSERT(int x,int v)
{
split(root,x+,left,oo);
node *tt=new node;
tt->v=v;tt->s=;tt->minn=v;tt->ch[]=tt->ch[]=null;
root=merge(merge(left,tt),oo);
}
void DELETE(int x)
{
split(root,x,left,oo);
split(oo,,mid,right);
root=merge(left,right);
}
void MIN(int a,int b)
{
split(root,a,left,oo);
split(oo,b-a+,mid,right);
printf("%lld\n",mid->minn);
root=merge(merge(left,mid),right);
}
void REVOLVE(int a,int b,int c)
{
if(!c) return;
node *tt;
split(root,a,left,oo);
split(oo,b-a+,mid,right); //切出[a,b]
split(mid,b-c-a+,tt,oo);//切出[a,b-c]
tt=merge(oo,tt);//合并即可
root=merge(merge(left,tt),right);
}
void ADD(int a,int b,int c)
{
//切出[a,b]
if(!c) return;
split(root,a,left,oo);
split(oo,b-a+,mid,right);
mid->add+=c;
mid->v+=c;
mid->minn+=c;
root=merge(merge(left,mid),right);
}
void REVERSE(int a,int b)
{
split(root,a,left,oo);
split(oo,b-a+,mid,right);
mid->flip^=;
root=merge(merge(left,mid),right);
}
int main()
{
//freopen("0.in","r",stdin);
//freopen("0.out","w",stdout);
int n,m,l,r,x;
char cmd[];
arr[]=<<;//前置结点防止干扰
while(scanf("%d",&n)!=EOF)
{
for(int i=;i<=n;i++)
scanf("%lld",&arr[i]);
build(,n,root);
scanf("%d",&m);
while(m--)
{
scanf("%s",cmd);
if(!strcmp(cmd,"ADD"))
{
scanf("%d%d%d",&l,&r,&x);
ADD(l,r,x);
}
if(!strcmp(cmd,"REVERSE"))
{
scanf("%d%d",&l,&r);
REVERSE(l,r);
}
if(!strcmp(cmd,"REVOLVE"))
{
scanf("%d%d%d",&l,&r,&x);
REVOLVE(l,r,(x%(r-l+)+(r-l+))%(r-l+));
}
if(!strcmp(cmd,"INSERT"))
{
scanf("%d%d",&l,&x);
INSERT(l,x);
}
if(!strcmp(cmd,"DELETE"))
{
scanf("%d",&l);
DELETE(l);
}
if(!strcmp(cmd,"MIN"))
{
scanf("%d%d",&l,&r);
MIN(l,r);
}
}
root=left=right=oo=null;
}
}
13476518 | neopenx | 3580 | Accepted | 8680K | 1047MS | C++ | 4510B | 2014-09-25 17:10:36 |
POJ 3580 (伸展树)的更多相关文章
- poj 3580 SuperMemo
题目连接 http://poj.org/problem?id=3580 SuperMemo Description Your friend, Jackson is invited to a TV sh ...
- poj_3580 伸展树
自己伸展树做的第一个题 poj 3580 supermemo. 题目大意 对一个数组进行维护,包含如下几个操作: ADD x, y, d 在 A[x]--A[y] 中的每个数都增加d REVERSE ...
- 伸展树Splay
新学的,其实吧,就那么回事.... 看了几天,splay处理序列问题,真的非常厉害,翻转,插入,删除,线段树实现不了的功能,splay用起来很方便. POJ 3580 SuperMemo 这题基本就是 ...
- POJ 3580(SuperMemo-Splay区间加)[template:Splay V2]
SuperMemo Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 11384 Accepted: 3572 Case T ...
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- 纸上谈兵:伸展树(splay tree)
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...
- SplayTree伸展树的非递归实现(自底向上)
Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...
- 伸展树(一)之 图文解析 和 C语言的实现
概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...
- 伸展树(二)之 C++的实现
概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...
随机推荐
- 基于 MeanShift 算法的目标跟踪问题研究
参考:http://www.cnblogs.com/tornadomeet/archive/2012/03/15/2398769.html MeanShift 算法作为一种基于特征的跟踪方法,基本思想 ...
- HDOJ 1102 生成树
Constructing Roads Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- BZOJ 1600
开始刷一些USACO月赛题了.. 这题简单递推就不说了. 然后我们发现暴力递推是$O(n^2)$的.看起来非常慢. 这道题拥有浓厚的数学色彩,因此我们可以从数学它的规律上找突破口. (于是暴力大法好, ...
- linux下复制一个文件的内容到另一个文件
cat path/to/file/filename1 >> path/to/file/filename2 例如: cat id_rsa.pub >> ~/.ssh/author ...
- Java动态加载类在功能模块开发中的作用
Java中我们一般会使用new关键字实例化对象然后调用该对象所属类提供的方法来实现相应的功能,比如我们现在有个主类叫Web类这个类中能实现各种方法,比如用户注册.发送邮件等功能,代码如下: /* * ...
- Java for LeetCode 189 Rotate Array
Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the array ...
- Girls and Boys(poj 1466)
题目描述: 给出一系列男女配对意愿信息.求一个集合中的最大人数,满足这个集合中两两的人不能配对. /* 二分图的最大独立集 因为没有给出具体的男生和女生,所以可以将数据扩大一倍,即n个男生,n个女生, ...
- opencv学习笔记(一)IplImage, CvMat, Mat 的关系
opencv学习笔记(一)IplImage, CvMat, Mat 的关系 opencv中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以代表和显示图像,但是,M ...
- Mysql DDL与DML
1,文件导入:LOAD DATA INFILE '/tmp/pet.txt' INTO TABLE pet FIELDS TERMINATED BY ',' LINES TERMINATED BY ' ...
- 《Algorithms算法》笔记:优先队列(2)——二叉堆
二叉堆 1 二叉堆的定义 堆是一个完全二叉树结构(除了最底下一层,其他层全是完全平衡的),如果每个结点都大于它的两个孩子,那么这个堆是有序的. 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组 ...