Segment Tree Beats 区间最值问题
Segment Tree Beats 区间最值问题
线段树一类特殊技巧!
引出:CF671C Ultimate Weirdness of an Array
其实是考试题,改题的时候并不会区间取最值,区间求和,之后秉承着好好学习的态度,学习了Segment tree Beats
套路是维护出区间最小值和次小值,以及区间最小值数量。之后再维护出题目中需要的东西就好了。之后怎么处理呢,如果我们需要维护出区间和x取max,那么,如果x<=minn[rt],那么直接return;如果x<minx[rt](minx[rt]为区间次小值),那么之间将最小值改成x,之后再改需要改的信息就好了...但是,如果x>=minx[rt],那么就递归处理子树信息。
什么?你说它的时间复杂度?每次修改均摊O(nlogn)
什么时候修改是O(n)呢,就是所有点的状态大概接近于1,2,1,2,1,2,1,2,1,2...之后对3取max,这种情况下单次修改是O(n)的,但是修改完这次之后,不论下一次修改是什么,都是O(1)的,并且,求和不会超过O(nlogn)
其实本质上,什么拖累了时间复杂度呢?就是当区间中不同的元素特别多的时候,单次修改的时间复杂度会较为高昂,但是假设,我们修改了A个元素,那么就相当于区间的集合中少了A-1个元素,并且我们知道这次修改最大是Alogn的,那么下一次修改就相当于少了A-1个不同元素,也就是说,假设没有这次修改,下一次修改B个元素的话,那么有了这次修改下一次就相当于修改了B-A+1个元素,那么我们考虑将所有的修改操作的时间复杂度求和,接近于O(nlogn),但是,这并不完全,因为每次修改可能会导致某些区间的元素个数增加。那么我们考虑会增加多少呢?因为所有修改的元素都修改成了一个值,那么就相当于有些区间的元素的个数多了1。那么修改的时间复杂度就是期望上(Qlogn+nlogn),但是其实并不会跑满,而且实际效率很快。
那么线段树的题嘛,考虑加上区间修改等操作的时间复杂度。因为每次区间覆盖的话,非常棒,取消了许多节点的独立性,时间复杂度完全没有问题!但是区间加的话假如一个区间的是1,2,3,4,5,6,1,2,3,4,5,6之后针对前6个区间加6,那么相当于增加了一倍的独立点个数,但是反过来考虑,构成1,2,3,4,5,6,1,2,3,4,5,6需要这种特殊构造,而特殊构造耗费的操作数量是接近n级别的,那么其实反过来考虑一下,时间复杂度没有任何问题,因为,其实我们考虑,只有区间修改的时间复杂度,是logn,那么为什么是O(logn)的原因是因为打了lazy标记,那么其实我们假装这里打了一个lazy标记,那么其实每次修改的节点只有log级别的,那么其实A也只增加了log级别的存在,而每次PushDown增加的也只是logn*Alogn其实也就是Alognlogn的时间复杂度。这非常正确,请不要反驳我。
那么我们考虑完时间复杂度了,是不是该讲题了?
并不是,因为例题没有那么多...
那么我们先举一个例子
给定一个长度为n的数列A,接下来有m次操作:
• 区间[l,r]中的所有数变成min(Ai,x)
• 询问区间[l,r]中所有数的和
• n,m≤50000 分块!(抱歉,我不会!)
• n,m ≤ 500000
裸题,按照上述要求维护一下就可以了,如果想写的话,可以联系我,我这里有我自己出的数据...
给定一个长度为n的数列A,接下来有m次操作:
• 区间[l,r]中的所有数变成min(Ai,x)
• 区间[l,r]中的所有数加上x(x可能是负数)
• 询问区间[l,r]中所有数的和
• n,m≤50000 分块!
• n,m ≤ 500000
同样是裸题,多了一个操作,HDU上有...题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5306
剩下的就是例题时间了!
BZOJ4355: Play with sequence
这个是不是有一点感觉了呢?
分析:其实还是区间操作裸题,我们对于操作1,之间区间覆盖,对于操作2先区间加,再区间取max...其实并不是很难对不对?对于操作3,之间输出1-n的最小值个数(如果最小值是0的话)
附上代码:
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 300505
#define ls rt<<1
#define rs rt<<1|1
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
ll minn[N<<2],minx[N<<2],cn[N<<2],cov[N<<2],add[N<<2];int n,Q;
void PushUp(int rt)
{
if(minn[ls]<minn[rs])minn[rt]=minn[ls],minx[rt]=min(minn[rs],minx[ls]),cn[rt]=cn[ls];
else if(minn[ls]==minn[rs])minn[rt]=minn[ls],minx[rt]=min(minx[rs],minx[ls]),cn[rt]=cn[ls]+cn[rs];
else minn[rt]=minn[rs],minx[rt]=min(minn[ls],minx[rs]),cn[rt]=cn[rs];
}
void PushDown(int m,int rt)
{
if(cov[rt]!=-1)minn[rs]=minn[ls]=cov[ls]=cov[rs]=cov[rt],cn[ls]=(m-(m>>1)),cn[rs]=(m>>1),minx[ls]=minx[rs]=1ll<<62,add[ls]=add[rs]=0,cov[rt]=-1;
if(add[rt])minn[ls]+=add[rt],minn[rs]+=add[rt],minx[ls]+=add[rt],minx[rs]+=add[rt],add[ls]+=add[rt],add[rs]+=add[rt],add[rt]=0;
if(minn[rt]>minn[ls])minn[ls]=minn[rt];if(minn[rt]>minn[rs])minn[rs]=minn[rt];
}
void build(int l,int r,int rt)
{
cov[rt]=-1,add[rt]=0;
if(l==r){scanf("%lld",&minn[rt]),minx[rt]=1ll<<62,cn[rt]=1;return;}
int m=(l+r)>>1;build(lson);build(rson);PushUp(rt);
}
void Update_cov(int L,int R,ll c,int l,int r,int rt)
{
if(L<=l&&r<=R){minn[rt]=cov[rt]=c,minx[rt]=1ll<<62,cn[rt]=r-l+1,add[rt]=0;return;}PushDown(r-l+1,rt);int m=(l+r)>>1;
if(L<=m)Update_cov(L,R,c,lson);if(m<R)Update_cov(L,R,c,rson);PushUp(rt);
}
void Update_add(int L,int R,ll c,int l,int r,int rt)
{
if(L<=l&&r<=R){minn[rt]+=c,add[rt]+=c,minx[rt]+=c;return;}PushDown(r-l+1,rt);int m=(l+r)>>1;
if(L<=m)Update_add(L,R,c,lson);if(m<R)Update_add(L,R,c,rson);PushUp(rt);
}
void Update_max(int L,int R,ll c,int l,int r,int rt)
{
if(c<=minn[rt])return ;
if(L<=l&&r<=R&&minx[rt]>c){minn[rt]=c;return ;}PushDown(r-l+1,rt);int m=(l+r)>>1;
if(L<=m)Update_max(L,R,c,lson);if(m<R)Update_max(L,R,c,rson);PushUp(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return minn[rt]?0:cn[rt];PushDown(r-l+1,rt);int m=(l+r)>>1;ll ret=0;
if(L<=m)ret+=query(L,R,lson);if(m<R)ret+=query(L,R,rson);return ret;
}
int main()
{
scanf("%d%d",&n,&Q);
build(1,n,1);
while(Q--)
{
int x,y,op;ll z;scanf("%d%d%d",&op,&x,&y);
if(op==1)scanf("%lld",&z),Update_cov(x,y,z,1,n,1);
else if(op==2)scanf("%lld",&z),Update_add(x,y,z,1,n,1),Update_max(x,y,0ll,1,n,1);
else printf("%lld\n",query(x,y,1,n,1));
}
return 0;
}
好吧好吧...其实例题目前只有一道...目测还有最假女选手什么的...好麻烦的说...
Segment Tree Beats 区间最值问题的更多相关文章
- BZOJ.4695.最假女选手(线段树 Segment tree Beats!)
题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...
- Segment tree Beats
Segment tree Beats Segment tree Beats,吉司机线段树,主要是关于如何用线段树实现区间取min/max.我们先看一道例题: HDU5306 Gorgeous Sequ ...
- [BZOJ4695]最假女选手:segment tree beats!
分析 segment tree beats!模板题. 看了gxz的博客突然发现自己写的mxbt和mnbt两个标记没用诶. 代码 #include <bits/stdc++.h> #defi ...
- [学习笔记]Segment Tree Beats!九老师线段树
对于这样一类问题: 区间取min,区间求和. N<=100000 要求O(nlogn)级别的算法 直观体会一下,区间取min,还要维护区间和 增加的长度很不好求.... 然鹅, 从前有一个来自杭 ...
- 【bzoj4695】最假女选手 线段树区间最值操作
题目描述 给定一个长度为 N 序列,编号从 1 到 N .要求支持下面几种操作:1.给一个区间[L,R] 加上一个数x 2.把一个区间[L,R] 里小于x 的数变成x 3.把一个区间[L,R] 里大于 ...
- 【bzoj4355】Play with sequence 线段树区间最值操作
题目描述 维护一个长度为N的序列a,现在有三种操作: 1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a[V]都赋值为C. 2)给出参数U,V,C,对于区间[U,V]里的每个数 ...
- 【hdu5306】Gorgeous Sequence 线段树区间最值操作
题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y ...
- picks loves segment tree I
picks loves segment tree I 题目背景 来源: \(\text {2018 WC Segment Tree Beats}\) 原作者: \(\text {C_SUNSHINE} ...
- SPOJ 11840. Sum of Squares with Segment Tree (线段树,区间更新)
http://www.spoj.com/problems/SEGSQRSS/ SPOJ Problem Set (classical) 11840. Sum of Squares with Segme ...
随机推荐
- flex做的圣杯布局
now,给大家分享一个用flex写的圣杯布局,大家可以参考一下子 首先圣杯布局是两列固定宽度,中间自适应. 我直接说一下步骤,上图,上图 1.步骤1 2.步骤2 上面就是基本的步骤,下面我把代码给大家 ...
- CSS让DIV按照背景图片的比例缩放,并让背景图片填充整个元素(转)
目的是:通过background的一系列属性,让DIV按照背景图片的比例缩放,并让背景图片填充整个DIV 首先我们需要让背景图片在指定的DIV中全部填充显示 之前看有用类似 background-at ...
- vue Element-UI 分页使用(1)
最近在使用Element-UI这套框架配合Vue来写前端页面.在用Element-UI来制作表格的时候,遇到了一些小问题,记录方便学习. 其中两个事件是关于切换当前页和切换显示的列表条数的.另外的属性 ...
- 使用CDN做网站的内容加速
1.什么是CDN: CDN的全称是Content Delivery Network,中文的意思就是内容分发网络,简单的讲通过现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的 ...
- arm64 调试环境搭建及 ROP 实战
前言 比赛的一个 arm 64 位的 pwn 题,通过这个题实践了 arm 64 下的 rop 以及调试环境搭建的方式. 题目文件 https://gitee.com/hac425/blog_data ...
- python中pip
经常在安装软件过程中用pip 安装,当时的我总觉得pip是给linux还有mac用的,所以就从没有仔细研究过pip,后来用了python才知道pip这么好用 今天总结一下pip的用法 我的电脑是win ...
- JAVA EE期末项目-校园小商店
校园小商店 一.项目成员及分工 我(计科二班袁文雪)和队友(计科二班蒋媛)设计了一款面对校园的网上购物商店. 我的工作:理解分析代码,编写文档. 二.项目需求分析 网上商店系统主要是实现学生网上选商品 ...
- 团队项目第二阶段个人进展——Day1
一.昨天工作总结 冲刺第一天,查看了第一阶段的代码 二.遇到的问题 写个的代码发现看不懂了 三.今日工作规划 重新设计页面布局
- .NET(C#)如何遍历Dictionary
我们知道.NET中的Dictionary是键/值对的集合,使用起来也是比较方便,Dictionary也可以用KeyValuePair来迭代遍历,具体如下: using System; using Sy ...
- LeetCode题解之Largest Number
1.题目描述 2. 将整数值转换为string ,然后排序. 3.代码 string largestNumber(vector<int>& nums) { vector<s ...