[学习笔记]Segment Tree Beats!九老师线段树
对于这样一类问题:
区间取min,区间求和。
N<=100000
要求O(nlogn)级别的算法
直观体会一下,区间取min,还要维护区间和
增加的长度很不好求。。。。
然鹅,
从前有一个来自杭州天水幼儿园的julao叫九条可怜
他发明了一个线段树的写法,
攻克了这个难题。
说起来很简单:
线段树维护区间最大值,区间严格次大值,和区间最大值出现次数
修改的时候,如果c大于mx,直接return
如果c小于mx而大于cmx,根据最大值的出现次数可以直接修改sum(注意必须是严格大于cmx,否则不能维护好严格次大值)
如果c小于等于cmx,那么暴力递归左右儿子,最终会用前两个更新,回溯来pushup一下
复杂度?
前两个O(1)就回溯了,不管。
第三个操作貌似有些暴力?
由于只有取max,所以
假如开始有O(N)个不同的值,那么每进行一次第三次操作,至少mx,和cmx要变得一样。值域减少1
那么,第三次操作最多进行O(n)次,每次均摊O(logn)
所以复杂度O(nlogn)
例题(以及一些具体操作):
bzoj4695. 最假女选手
【bzoj4695】最假女选手
区间还要加?值域会改变,,,可以证明(就是说我不会证)复杂度是O(nlog^2n)
维护区间最大值,次大值,最大值出现次数,最小值同理。以及区间和,区间加标记
下放:
先下放区间加标记,现在儿子的情况大致和父亲一样了
区别在于,之前区间取min可能把最大值砍掉一些,但是没有在儿子中更新。
由于仅最大值小了一些,所以如果父亲的最大值在儿子的最大值和次大值之间,那么暴力再让儿子对父亲的最大值取个min(直接返回的,这个也是O(1)的)
第二种情况的更新时候:
可能造成最大值和最小值相同的情况,那么必然就是全部都相等了。特判一下,把次大值-inf,最大值inf(其实这个没有必要)
或者可能只有值域只有两个,那么次大值或者次小值也要尝试更新一下。其他值域的时候不影响。(这个必须有)
代码比较长:
- #include<bits/stdc++.h>
- #define reg register int
- #define il inline
- #define mid ((l+r)>>1)
- #define ls t[x].lson
- #define rs t[x].rson
- #define numb (ch^'0')
- using namespace std;
- typedef long long ll;
- il void rd(int &x){
- char ch;x=;bool fl=false;
- while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
- for(x=numb;isdigit(ch=getchar());x=x*+numb);
- (fl==true)&&(x=-x);
- }
- namespace Miracle{
- const int N=6e5+;
- const int inf=0x3f3f3f3f;
- int n,m;
- int a[N];
- struct node{
- int mx,cmx,tmx;
- int mi,cmi,tmi;
- ll sum;
- ll ad;
- int lson,rson;
- }t[*N];
- int tot;
- void pushup(int x){
- t[x].sum=t[ls].sum+t[rs].sum;
- if(t[ls].mx>t[rs].mx){
- t[x].mx=t[ls].mx,t[x].tmx=t[ls].tmx;t[x].cmx=max(t[ls].cmx,t[rs].mx);
- }else if(t[ls].mx<t[rs].mx){
- t[x].mx=t[rs].mx,t[x].tmx=t[rs].tmx;t[x].cmx=max(t[rs].cmx,t[ls].mx);
- }else{
- t[x].mx=t[ls].mx;t[x].tmx=t[ls].tmx+t[rs].tmx;t[x].cmx=max(t[rs].cmx,t[ls].cmx);
- }
- if(t[ls].mi<t[rs].mi){
- t[x].mi=t[ls].mi,t[x].tmi=t[ls].tmi;t[x].cmi=min(t[ls].cmi,t[rs].mi);
- }else if(t[ls].mi>t[rs].mi){
- t[x].mi=t[rs].mi,t[x].tmi=t[rs].tmi;t[x].cmi=min(t[rs].cmi,t[ls].mi);
- }else{
- t[x].mi=t[ls].mi;t[x].tmi=t[ls].tmi+t[rs].tmi;t[x].cmi=min(t[rs].cmi,t[ls].cmi);
- }
- }
- void addmax(int x,int l,int r,int c){//qu max
- t[x].sum+=(ll)t[x].tmi*(c-t[x].mi);
- t[x].mi=c;
- t[x].mx=max(t[x].mx,c);
- if(t[x].mi==t[x].mx){
- t[x].sum=((ll)r-l+)*c;t[x].tmi=t[x].tmx=r-l+;t[x].cmi=inf;t[x].cmx=-inf;
- }else t[x].cmx=max(t[x].cmx,c);
- }
- void addmin(int x,int l,int r,int c){
- t[x].sum+=(ll)t[x].tmx*(c-t[x].mx);
- t[x].mx=c;
- t[x].mi=min(t[x].mi,c);
- if(t[x].mi==t[x].mx){
- t[x].sum=((ll)r-l+)*c;t[x].tmi=t[x].tmx=r-l+;t[x].cmi=inf;t[x].cmx=-inf;
- }else t[x].cmi=min(t[x].cmi,c);
- }
- void build(int x,int l,int r){
- if(l==r){
- t[x].mx=t[x].mi=a[l];
- t[x].cmx=-inf;t[x].cmi=inf;
- t[x].tmx=t[x].tmi=;
- t[x].sum=a[l];return;
- }
- ls=++tot;rs=++tot;
- build(ls,l,mid);build(rs,mid+,r);
- pushup(x);
- }
- void getsum(int x,int l,int r,int c){
- t[x].ad+=c;t[x].sum+=(r-l+)*c;
- t[x].mi+=c;t[x].cmi+=c;
- t[x].mx+=c;t[x].cmx+=c;
- }
- void pushdown(int x,int l,int r){
- if(t[x].ad){
- getsum(ls,l,mid,t[x].ad);
- getsum(rs,mid+,r,t[x].ad);
- t[x].ad=;
- }
- if(t[ls].mx>t[x].mx&&t[ls].cmx<t[x].mx) addmin(ls,l,mid,t[x].mx);
- if(t[rs].mx>t[x].mx&&t[rs].cmx<t[x].mx) addmin(rs,mid+,r,t[x].mx);
- if(t[ls].mi<t[x].mi&&t[ls].cmi>t[x].mi) addmax(ls,l,mid,t[x].mi);
- if(t[rs].mi<t[x].mi&&t[rs].cmi>t[x].mi) addmax(rs,mid+,r,t[x].mi);
- }
- void chanmx(int x,int l,int r,int L,int R,int c){
- //cout<<x<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<c<<" "<<t[x].cmi<<endl;
- if(L<=l&&r<=R){
- if(t[x].mi>=c) return;
- if(t[x].cmi>c) {
- addmax(x,l,r,c);return;
- }
- pushdown(x,l,r);
- chanmx(ls,l,mid,L,R,c);
- chanmx(rs,mid+,r,L,R,c);
- pushup(x);
- return;
- }
- pushdown(x,l,r);
- if(L<=mid) chanmx(ls,l,mid,L,R,c);
- if(mid<R) chanmx(rs,mid+,r,L,R,c);
- pushup(x);
- }
- void chanmi(int x,int l,int r,int L,int R,int c){
- if(L<=l&&r<=R){
- if(t[x].mx<=c) return;
- if(t[x].cmx<c) {
- addmin(x,l,r,c);return;
- }
- pushdown(x,l,r);
- chanmi(ls,l,mid,L,R,c);
- chanmi(rs,mid+,r,L,R,c);
- pushup(x);
- return;
- }
- pushdown(x,l,r);
- if(L<=mid) chanmi(ls,l,mid,L,R,c);
- if(mid<R) chanmi(rs,mid+,r,L,R,c);
- pushup(x);
- }
- void add(int x,int l,int r,int L,int R,int c){
- if(L<=l&&r<=R){
- getsum(x,l,r,c);
- return;
- }
- pushdown(x,l,r);
- if(L<=mid) add(ls,l,mid,L,R,c);
- if(mid<R) add(rs,mid+,r,L,R,c);
- pushup(x);
- }
- int qmax(int x,int l,int r,int L,int R){
- if(L<=l&&r<=R){
- return t[x].mx;
- }
- pushdown(x,l,r);int ret=-inf;
- if(L<=mid) ret=max(ret,qmax(ls,l,mid,L,R));
- if(mid<R) ret=max(ret,qmax(rs,mid+,r,L,R));
- return ret;
- }
- int qmin(int x,int l,int r,int L,int R){
- if(L<=l&&r<=R){
- return t[x].mi;
- }
- pushdown(x,l,r);int ret=inf;
- if(L<=mid) ret=min(ret,qmin(ls,l,mid,L,R));
- if(mid<R) ret=min(ret,qmin(rs,mid+,r,L,R));
- return ret;
- }
- ll qsum(int x,int l,int r,int L,int R){
- if(L<=l&&r<=R){
- return t[x].sum;
- }
- pushdown(x,l,r);ll ret=;
- if(L<=mid) ret+=qsum(ls,l,mid,L,R);
- if(mid<R) ret+=qsum(rs,mid+,r,L,R);
- return ret;
- }
- int main(){
- rd(n);
- for(reg i=;i<=n;++i){
- rd(a[i]);
- }
- rd(m);
- ++tot;
- build(,,n);
- //cout<<" tot "<<tot<<endl;
- int op,l,r,x;
- int o=;
- while(m--){
- ++o;
- // cout<<" oooo "<<o<<endl;
- rd(op);
- switch(op){
- case :rd(l);rd(r);rd(x);add(,,n,l,r,x);break;
- case :rd(l);rd(r);rd(x);chanmx(,,n,l,r,x);break;
- case :rd(l);rd(r);rd(x);chanmi(,,n,l,r,x);break;
- case :rd(l);rd(r);printf("%lld\n",qsum(,,n,l,r));break;
- case :rd(l);rd(r);printf("%d\n",qmax(,,n,l,r));break;
- case :rd(l);rd(r);printf("%d\n",qmin(,,n,l,r));break;
- }
- }
- return ;
- }
- }
- signed main(){
- Miracle::main();
- return ;
- }
- /*
- Author: *Miracle*
- Date: 2018/12/27 9:57:30
- */
不亏是九老师自己出的题
[学习笔记]Segment Tree Beats!九老师线段树的更多相关文章
- [LintCode] Segment Tree Build II 建立线段树之二
The structure of Segment Tree is a binary tree which each node has two attributes startand end denot ...
- Segment Tree Beats 区间最值问题
Segment Tree Beats 区间最值问题 线段树一类特殊技巧! 引出:CF671C Ultimate Weirdness of an Array 其实是考试题,改题的时候并不会区间取最值,区 ...
- 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 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十九章:法线贴图
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十九章:法线贴图 学习目标 理解为什么需要法线贴图: 学习法线贴图如 ...
- ACM学习历程——POJ3321 Apple Tree(搜索,线段树)
Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will ...
- ACM学习历程——NOJ1113 Game I(贪心 || 线段树)
Description 尼克发明了这样一个游戏:在一个坐标轴上,有一些圆,这些圆的圆心都在x轴上,现在给定一个x轴上的点,保证该点没有在这些圆内(以及圆上),尼克可以以这个点为圆心做任意大小的圆,他想 ...
- [学习笔记]dsu on a tree(如何远离线段树合并)
https://www.zybuluo.com/ysner/note/1318613 背景 这玩意来源于一种有局限性的算法. 有一种广为人知的,树上离线维护子树信息的做法. (可以参照luogu360 ...
随机推荐
- 第四篇 与Flask相关的插件(flask-session、wtforms)
公司中使用SQL的种方式: 1. 写Django:ORM(关系对象映射), 2. 写Flask和其他:有两种方式: (1) 原生SQL:使用原生SQL有两种选择: A. pymysql (python ...
- 254. Drop Eggs【LintCode java】
Description There is a building of n floors. If an egg drops from the k th floor or above, it will b ...
- Java学习笔记-11.运行期间类型鉴定
1.Class对象的getClasses()方法获取的是该类中所有的公共的内部类,以及从父类,父接口继承来的内部类.getinterfaces()方法返回类继承的所有接口. import javax. ...
- 图像质量评价指标之 PSNR 和 SSIM
1. PSNR (Peak Signal-to-Noise Ratio) 峰值信噪比 给定一个大小为 \(m×n\) 的干净图像 \(I\) 和噪声图像 \(K\),均方误差 \((MSE)\) 定义 ...
- canvas学习(二):渐变与曲线的绘制
canvas学习(二):渐变与曲线的绘制 一:createLinearGradient()线性渐变: 二:createLinearGradient() 放射状/圆形渐变: 三:createPatter ...
- 2017秋-软件工程第四次作业(2)-结对使用TDD框架完成单元测试
第一次接触“单元测试”这个要求,我和队友学习了一些示例后开始操作.如下展示一些建立单元测试的过程.Step1:右键单击[解决方案]->左键单击[添加(D)]->[新建项目(N)]. Ste ...
- lintcode-17-子集
子集 给定一个含不同整数的集合,返回其所有的子集 注意事项 子集中的元素排列必须是非降序的,解集必须不包含重复的子集 样例 如果 S = [1,2,3],有如下的解: [ [3], [1], [2], ...
- Linux内核策略介绍学习笔记
主要内容 硬件 策略 CPU 进程调度.系统调用.中断 内存 内存管理 外存 文件IO 网络 协议栈 其他 时间管理 进程调度 内核的运行时间 系统启动.中断发生.系统调用以及内核线程. 进程和线程的 ...
- 基于实现Controller接口的简单Spring工程
这个Spring工程的特点是:实现了Controller接口(这样就可以在url中传参数?,待调查) 一下为代码,可运行. 1,web.xml <servlet> <servlet- ...
- EasyUI 学习笔记
EasyUI常见错误 1 . 无论是用HMTL形式实现组件还是使用代码 + HTML 形式实现组件 , 在为组件设置属性时 , 要注意属性值的类型问题 string:必须加引号 number:不加任何 ...