题目链接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 (伸展树)的更多相关文章

  1. poj 3580 SuperMemo

    题目连接 http://poj.org/problem?id=3580 SuperMemo Description Your friend, Jackson is invited to a TV sh ...

  2. poj_3580 伸展树

    自己伸展树做的第一个题 poj 3580 supermemo. 题目大意 对一个数组进行维护,包含如下几个操作: ADD x, y, d 在 A[x]--A[y] 中的每个数都增加d REVERSE ...

  3. 伸展树Splay

    新学的,其实吧,就那么回事.... 看了几天,splay处理序列问题,真的非常厉害,翻转,插入,删除,线段树实现不了的功能,splay用起来很方便. POJ 3580 SuperMemo 这题基本就是 ...

  4. POJ 3580(SuperMemo-Splay区间加)[template:Splay V2]

    SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11384   Accepted: 3572 Case T ...

  5. Splay伸展树学习笔记

    Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...

  6. 纸上谈兵:伸展树(splay tree)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...

  7. SplayTree伸展树的非递归实现(自底向上)

    Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...

  8. 伸展树(一)之 图文解析 和 C语言的实现

    概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...

  9. 伸展树(二)之 C++的实现

    概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...

随机推荐

  1. crontab报错

    $mail 选择对应的数字查看邮件 File "/opt/app/python/tv-cms-for-ch/current/scripts/sync_cms_for_ch.py", ...

  2. 关于 datasnap Stream的英文博客能容

    转载:http://blogs.embarcadero.com/jimtierney/2009/04/06/31461/ DataSnap Server Method Stream Parameter ...

  3. [颓废] 改某人的WebGL light mapping demo并9xSSAA

    渲染图(4k) 链接: http://pan.baidu.com/s/1bnB4Wqz 密码: 8839 2px高斯模糊+立方缩小AA:  链接: http://pan.baidu.com/s/1mg ...

  4. 深入学习微框架:Spring Boot - NO

    http://blog.csdn.net/hengyunabc/article/details/50120001 Our primary goals are: Provide a radically ...

  5. RadioButtonList单选和RequiredFieldValidator验证是否选中

    <asp:RadioButtonList ID="Radio2" RepeatDirection="Horizontal" runat="ser ...

  6. tesseract3.02识别验证码需要注意的问题

    1.安装tesseract3.02后,在命令行里输入tesseract,看能否出现使用方法,不出现则是环境变量问题,可调整其顺序. 2.找到如下文件 C:\Python27\Lib\site-pack ...

  7. 20. 最长公共子串(ToDo)[LCS]

    [参考] http://zhedahht.blog.163.com/blog/static/254111742007376431815/

  8. mybatis的insert简单使用

  9. excel数据导入SQLite数据库

    参考:http://blog.baisi.net/?110653/viewspace-6725 1.excel表中最上面一行的字段名留着,留着以后导入的时候对应. 2.保存成csv格式,在选择文件类型 ...

  10. javascript中json解密

    一直以前都会断断续续会碰到js中的json数据的解析,下面凭着自己的经验,简单的讲解一下在js中的json的几种解析方法.  一.jquery的方式 首先你得先得到数据,一般都是jquery的ajax ...