前言

这篇博客是根据我在打这道题的时候遇到的问题,来打的,有些细节可能考虑不到。

题目

在N(1<=N<=100000)个数A1…An组成的序列上进行M(1<=M<=100000)次操作,操作有两种:

(1)1 L R C:表示把A[L]到A[R]增加C(C的绝对值不超过10000);

(2)2 L R:询问A[L]到A[R]之间的最大值。

分析

由于本人刚刚学会splay,不够精通,splay的打法这里就先不说。

就讲讲求区间极值的方法吧。

对于每个位置开一个节点,记录这个节点的值、在以它为根的子树中的最大值。

当我们要对一个区间进行查询或修改时,

假设修改的区级为\([l,r]\)

我们将l-1转到根节点,r+1转到根节点的右儿子(为了保证有l-1和r+1节点,另外加入0和n+1节点)

那么根据二叉查找树的性质,

r+1的左子树就是要查询或修改的区间。



接着,还要处理lazy标记,

当我们再将x节点转到y节点的儿子时只需从y到x,将标记全部下传就可以了。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=100005;
using namespace std;
int l[N],r[N],lazy[N],mx[N],a[N],fa[N],root,q1,q2;
int tot,n,m,ans;
void clear()
{
fa[0]=lazy[0]=l[0]=r[0]=0;
mx[1]=mx[tot]=a[1]=a[tot]=mx[0]=a[0]=-maxlongint;
}
void doda(int x,int z)
{
mx[x]+=z;
a[x]+=z;
lazy[x]+=z;
}
void down(int x)
{
int z=lazy[x];
if(!z) return;
doda(l[x],z);
doda(r[x],z);
lazy[x]=0;
}
int getmax(int x)
{
mx[x]=max(mx[l[x]],mx[r[x]]);
mx[x]=max(mx[x],a[x]);
}
void zig(int x)
{
int y=fa[x];
fa[r[x]]=y;
if(l[fa[fa[x]]]==fa[x]) l[fa[y]]=x;
else r[fa[y]]=x;
l[y]=r[x];
r[x]=y;
fa[x]=fa[y];
fa[y]=x;
getmax(y);
getmax(x);
}
void zag(int x)
{
int y=fa[x];
fa[l[x]]=y;
if(l[fa[fa[x]]]==fa[x]) l[fa[y]]=x;
else r[fa[y]]=x;
r[y]=l[x];
l[x]=y;
fa[x]=fa[y];
fa[y]=x;
getmax(y);
getmax(x);
}
void splay(int p,int x)
{
if(x==p) return;
while(fa[x]!=p)
{
if(fa[fa[x]]==p)
{
if(l[fa[x]]==x) zig(x);
else zag(x);
break;
}
q1=(l[fa[fa[x]]]==fa[x]),q2=(l[fa[x]]==x);
if(q1)
{
if(q2) zig(fa[x]),zig(x);
else zag(x),zig(x);
}
else
{
if(q2) zig(x),zag(x);
else zag(fa[x]),zag(x);
}
}
}
void sola(int v,int x)
{
down(v);
if(x<v) sola(l[v],x);
if(v<x) sola(r[v],x);
getmax(v);
}
int get(int ll,int rr)
{
sola(root,ll-1);
clear();
splay(0,ll-1);
root=ll-1;
sola(root,rr+1);
clear();
splay(ll-1,rr+1);
return l[rr+1];
}
int main()
{
scanf("%d",&n);
r[1]=2;
fa[2]=1;
tot=2;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[tot]);
mx[tot]=a[tot];
fa[tot+1]=tot;
r[tot]=++tot;
}
clear();
for(int i=tot;i>=1;i--) mx[i]=max(a[i],mx[r[i]]);
root=1;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x,ll,rr,c;
scanf("%d%d%d",&x,&ll,&rr);
ll++;
rr++;
clear();
if(x==1) scanf("%d",&c),doda(get(ll,rr),c);
else printf("%d\n",mx[get(ll,rr)]);
}
}

后记(2018.4.28)

明天就是GDOI2018了,回顾自己以前写的博客,看到我打splay居然zig、zag分开的之类的,回忆我多年来的OI历程,有些感慨。

总之,GDOI2018,加油。

伸展树splay之求区间极值的更多相关文章

  1. 伸展树(Splay tree)的基本操作与应用

    伸展树的基本操作与应用 [伸展树的基本操作] 伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性.即伸展树中的每一个节点 x 都满足:该节点左子树中的每一个元素都小于 x,而其右子树中 ...

  2. K:伸展树(splay tree)

      伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...

  3. 树-伸展树(Splay Tree)

    伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...

  4. 纸上谈兵: 伸展树 (splay tree)[转]

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

  5. 高级搜索树-伸展树(Splay Tree)

    目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...

  6. 【BBST 之伸展树 (Splay Tree)】

    最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...

  7. [Splay伸展树]splay树入门级教程

    首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...

  8. 伸展树Splay【非指针版】

    ·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...

  9. POJ 3580 - SuperMemo - [伸展树splay]

    题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...

随机推荐

  1. 浏览器从输入URL到渲染出页面发生了什么

    总体来说分为以下几个过程: 1.  DNS解析 2. TCP连接 3. 发送HTTP请求 4. 服务器处理请求并返回HTTP报文 5. 浏览器解析渲染页面 6. 连接结束 参考资料:[https:// ...

  2. mnist数据集下载——mnist数据集提供百度网盘下载地址

    mnist数据集是由深度学习大神 LeCun等人制作完成的数据集,mnist数据集也常认为是深度学习的“ Hello World!”. 官网:http://yann.lecun.com/exdb/mn ...

  3. 字符串转Interger

    public static void main(String[] args) { String t = "5"; Integer integer = Integer.valueOf ...

  4. ucloud建新主机

    系统盘默认20G,可调到40不增加费用.需建好主机后关机才能更改. root密码按统一的设 设好主机名,选好分组

  5. 思考--mysql 分库分表的思考

    查询不在分库键上怎么办,扫描所有库?由于分库了,每个库扫描很快?所以比单个表的扫描肯定快,可以这样理解吗. 多表jion怎么弄,把内层表发给每个分库吗? citus,tidb 都有这些问题,citus ...

  6. 微软宣布加入 OpenJDK,打不过就改变 Java 未来!

    近日,微软的 Bruno Borges 在 OpenJDK 邮件列表中发布了一条消息,内容包含接下来发生的事情以及微软如何开始将其团队整合到 OpenJDK 社区. 在邮件中,Bruno Borges ...

  7. 【提高组NOIP2008】双栈排序 (twostack.pas/c/cpp)

    [题目描述] Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈 ...

  8. 问题:C++类的静态成员变量如何初始化

    C++类的静态成员变量属于该类,在该类所有的对象间共享. 要弄清如何初始化,首先要明白声明.定义.初始化三个概念的不同. 声明:指定变量的名字和类型,可以多次声明. 定义:为该成员变量分配存储空间,有 ...

  9. GitHub编辑README.md

    一.标题 等级表示法(六级): #一级标题 ##二级标题 ###三级标题 ####四级标题 #####五级标题 ######六级标题 一级标题/大标题(文本下面加上等于号): 大标题 === 二级标题 ...

  10. 0-1-Tree CodeForces - 1156D (并查集)

    大意: 给定树, 边权为黑或白, 求所有有向路径条数, 满足每走过一条黑边后不会走白边. 这题比赛的时候想了个假算法, 还没发现..... 显然所求的路径要么全黑, 要么全白, 要么先全白后全黑, 所 ...