题目链接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. Android控件之圆形Button

    bg_circle.xml <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns: ...

  2. Linux Tomcat 简介

    如今,基于Web的应用越来越多,传统的Html已经满足不了如今的需求.我们需要一个交互式的Web,于是便诞生了各种Web语言.如Asp,Jsp,Php等.当然,这些语言与传统的语言有着密切的联系,如P ...

  3. python - PyQuery

    偶尔的机会,知道这么个扩展,手贱翻了下文档,发现似乎挺有意思,遂记录一二. what: 这是一个python版本的jquery,而且是后端执行的,至少官方是这么说的: pyquery allows y ...

  4. PHP 冒泡原理

    header('Content-Type: text/html; charset=utf-8'); // 简单冒泡算法 $a = array(5,43,3,2,1); function mp($a){ ...

  5. iOS CALayer动画中使用的3个tree

    在网上经常看到关于layer的tree的描述,不太理解,今天找到了官方文档,原文在Core Animation Programming Guide 中. Layer Trees Reflect Dif ...

  6. Java for LeetCode 069 Sqrt(x)

    Implement int sqrt(int x). Compute and return the square root of x. 解题思路一: public int mySqrt(int x) ...

  7. 使用Memory Analyzer tool(MAT)分析内存泄漏(一)

    转载自:http://www.blogjava.net/rosen/archive/2010/05/21/321575.html 前言 在平时工作过程中,有时会遇到OutOfMemoryError,我 ...

  8. fedora 添加其他操作系统到 GRUB 2 菜单

    # yum install os-prober # grub2-mkconfig -o /boot/grub2/grub.cfg

  9. Myeclipse 安装svn插件

    安装subclipse,  SVN插件1.从官网下载site-1.8.22.zip文件  访问不了可点我网盘2.从中解压出features与 plugins文件夹,复制到MyEclipse\MyEcl ...

  10. 【Ubuntu日常技巧】VirtualBox多网卡路由配置,保障虚拟机连接上外网

    [背景]: 配置Ubuntu 虚拟机双网卡,一个是Host-Only网络,一个是桥接网络.当在虚拟机中同时连接到两个网络后,虚拟机能够ping通内部网络,不能ping通外部网络,如www.baidu. ...