传送门

线段树好题。

维护区间加,区间取最大值,维护区间最小值,历史区间最小值。

同样先考虑不用维护历史区间最小值的情况,这个可以参考这道题的解法,维护区间最小和次小值可以解决前两个操作,然后使用历史标记的常规维护方式合并标记更新就行了。

代码:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define N 500005
#define inf 2000000030
using namespace std;
struct Node{int l,r,sn,mn,add,his,his_add,his_mn,f;}T[N<<2];
int n,m,a[N];
inline int read(){
    int ans=0,w=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans*w;
}
inline int min(int a,int b){return a<b?a:b;}
inline void pushup(int p){
    T[p].his=min(T[lc].his,T[rc].his),T[lc].f=T[rc].f=0,T[p].mn=min(T[lc].mn,T[rc].mn);
    T[p].sn=min(T[p].mn==T[lc].mn?T[lc].sn:T[lc].mn,T[p].mn==T[rc].mn?T[rc].sn:T[rc].mn);
    if(T[lc].mn==T[p].mn)T[lc].f=1;
    if(T[rc].mn==T[p].mn)T[rc].f=1;
}
inline void pushadd(int p,int v){
    T[p].his_add=min(T[p].his_add,T[p].add+=v),T[p].sn+=v;
    T[p].his=min(T[p].his,T[p].mn+=v),T[p].his_mn=min(T[p].his_mn,T[p].mn);
}
inline void pushset(int p,int v){if(T[p].mn>=v)return;T[p].mn=v;}
inline void pushdown(int p){
    if(T[lc].f)T[lc].his=min(T[lc].his,T[p].his_mn),T[lc].his_mn=min(T[lc].his_mn,T[p].his_mn);
    else T[lc].his=min(T[lc].his,T[lc].mn+T[p].his_add),T[lc].his_mn=min(T[lc].his_mn,T[lc].mn+T[p].his_add);
    if(T[rc].f)T[rc].his=min(T[rc].his,T[p].his_mn),T[rc].his_mn=min(T[rc].his_mn,T[p].his_mn);
    else T[rc].his=min(T[rc].his,T[rc].mn+T[p].his_add),T[rc].his_mn=min(T[rc].his_mn,T[rc].mn+T[p].his_add);
    T[lc].mn+=T[p].add,T[rc].mn+=T[p].add,T[lc].sn+=T[p].add,T[rc].sn+=T[p].add;
    T[lc].his_add=min(T[lc].his_add,T[lc].add+T[p].his_add);
    T[rc].his_add=min(T[rc].his_add,T[rc].add+T[p].his_add);
    T[lc].add+=T[p].add,T[rc].add+=T[p].add;
    if(T[lc].mn<T[p].mn)T[lc].mn=T[p].mn;
    if(T[rc].mn<T[p].mn)T[rc].mn=T[p].mn;
    T[p].add=0,T[p].his_add=0,T[p].his_mn=inf;
}
inline void build(int p,int l,int r){
    T[p].l=l,T[p].r=r,T[p].add=T[p].his_add=0,T[p].his_mn=inf;
    if(l==r){T[p].his=T[p].mn=a[l],T[p].sn=inf;return;}
    build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int ql,int qr,int v){
    if(ql>T[p].r||qr<T[p].l)return;
    if(ql<=T[p].l&&T[p].r<=qr)return pushadd(p,v);
    pushdown(p);
    if(qr<=mid)update(lc,ql,qr,v);
    else if(ql>mid)update(rc,ql,qr,v);
    else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
    pushup(p);
}
inline void modify(int p,int ql,int qr,int v){
    if(ql>T[p].r||qr<T[p].l||T[p].mn>=v)return;
    if(ql<=T[p].l&&T[p].r<=qr&&T[p].sn>v)return pushset(p,v);
    pushdown(p);
    if(qr<=mid)modify(lc,ql,qr,v);
    else if(ql>mid)modify(rc,ql,qr,v);
    else modify(lc,ql,mid,v),modify(rc,mid+1,qr,v);
    pushup(p);
}
inline int query(int p,int ql,int qr,int k){
    if(ql>T[p].r||qr<T[p].l)return inf;
    if(ql<=T[p].l&&T[p].r<=qr)return k==3?T[p].mn:T[p].his;
    pushdown(p);
    if(qr<=mid)return query(lc,ql,qr,k);
    if(ql>mid)return query(rc,ql,qr,k);
    return min(query(lc,ql,mid,k),query(rc,mid+1,qr,k));
}
int main(){
    n=read(),m=read();
    for(register int i=1;i<=n;++i)a[i]=read();
    build(1,1,n);
    while(m--){
        int op=read(),l=read(),r=read();
        if(op==1){int v=read();update(1,l,r,v);}
        else if(op==2){int v=read();modify(1,l,r,v);}
        else printf("%d\n",query(1,l,r,op));
    }
    return 0;
}

update

在做了Picks loves segment tree VIII之后学习了新的写法,然后重新写了一遍。

代码:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define N 500005
#define inf 2e9
using namespace std;
inline int read(){
    int ans=0,w=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans*w;
}
struct Min{int his,mn,sn;};
struct tag{int add,mnadd;};
struct Node{int l,r;Min mn;tag Amin,Bmid;}T[N<<2];
int n,m,a[N];
inline int min(int a,int b){return a<b?a:b;}
inline tag operator+(tag a,int v){return (tag){a.add+v,min(a.mnadd,a.add+v)};}
inline tag operator+(tag a,tag b){return (tag){a.add+b.add,min(a.mnadd,b.mnadd+a.add)};}
inline Min operator+(Min a,Min b){return (Min){min(a.his,b.his),min(a.mn,b.mn),a.mn==b.mn?min(a.sn,b.sn):(a.mn>b.mn?min(a.mn,b.sn):min(a.sn,b.mn))};}
inline void pushup(int p){T[p].mn=T[lc].mn+T[rc].mn;}
inline void pushadd(int p,int v){
    T[p].mn.his=min(T[p].mn.his,T[p].mn.mn+=v);
    if(T[p].mn.sn!=inf)T[p].mn.sn+=v;
    T[p].Amin=T[p].Amin+v,T[p].Bmid=T[p].Bmid+v;
}
inline void pushAmin(int p,tag v){
    T[p].mn.his=min(T[p].mn.his,T[p].mn.mn+v.mnadd);
    T[p].mn.mn+=v.add;
    T[p].Amin=T[p].Amin+v;
}
inline void pushBmid(int p,tag v){
    if(T[p].mn.sn!=inf)T[p].mn.sn+=v.add;
    T[p].Bmid=T[p].Bmid+v;
}
inline void pushdown(int p){
    int tmpmn=min(T[lc].mn.mn,T[rc].mn.mn);
    if(tmpmn==T[lc].mn.mn)pushAmin(lc,T[p].Amin);
    else pushAmin(lc,T[p].Bmid);
    pushBmid(lc,T[p].Bmid);
    if(tmpmn==T[rc].mn.mn)pushAmin(rc,T[p].Amin);
    else pushAmin(rc,T[p].Bmid);
    pushBmid(rc,T[p].Bmid);
    T[p].Amin=T[p].Bmid=(tag){0,0};
}
inline void build(int p,int l,int r){
    T[p].l=l,T[p].r=r,T[p].Amin=T[p].Bmid=(tag){0,0};
    if(l==r){T[p].mn=(Min){a[l],a[l],inf};return;}
    build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int ql,int qr,int v){
    if(ql>T[p].r||qr<T[p].l)return;
    if(ql<=T[p].l&&T[p].r<=qr)return pushadd(p,v);
    pushdown(p);
    if(qr<=mid)update(lc,ql,qr,v);
    else if(ql>mid)update(rc,ql,qr,v);
    else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
    pushup(p);
}
inline void updmin(int p,int ql,int qr,int v){
    if(ql>T[p].r||qr<T[p].l||T[p].mn.mn>=v)return;
    if(ql<=T[p].l&&T[p].r<=qr&&T[p].mn.sn>v)return pushAmin(p,(tag){v-T[p].mn.mn,0});
    pushdown(p);
    if(qr<=mid)updmin(lc,ql,qr,v);
    else if(ql>mid)updmin(rc,ql,qr,v);
    else updmin(lc,ql,mid,v),updmin(rc,mid+1,qr,v);
    pushup(p);
}
inline int query(int p,int ql,int qr){
    if(ql>T[p].r||qr<T[p].l)return inf;
    if(ql<=T[p].l&&T[p].r<=qr)return T[p].mn.mn;
    pushdown(p);
    if(qr<=mid)return query(lc,ql,qr);
    if(ql>mid)return query(rc,ql,qr);
    return min(query(lc,ql,mid),query(rc,mid+1,qr));
}
inline int querymn(int p,int ql,int qr){
    if(ql>T[p].r||qr<T[p].l)return inf;
    if(ql<=T[p].l&&T[p].r<=qr)return T[p].mn.his;
    pushdown(p);
    if(qr<=mid)return querymn(lc,ql,qr);
    if(ql>mid)return querymn(rc,ql,qr);
    return min(querymn(lc,ql,mid),querymn(rc,mid+1,qr));
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i)a[i]=read();
    build(1,1,n);
    while(m--){
        int op=read(),l=read(),r=read();
        if(op==1){int v=read();update(1,l,r,v);}
        if(op==2){int v=read();updmin(1,l,r,v);}
        if(op==3)printf("%d\n",query(1,l,r));
        if(op==4)printf("%d\n",querymn(1,l,r));
    }
    return 0;
}

2018.07.28 uoj#169. 【UR #11】元旦老人与数列(线段树)的更多相关文章

  1. 2018.07.28 uoj#164. 【清华集训2015】V(线段树)

    传送门 线段树好题. 要求支持的操作: 1.区间变成max(xi−a,0)" role="presentation" style="position: rela ...

  2. 2018.07.29~30 uoj#170. Picks loves segment tree VIII(线段树)

    传送门 线段树好题. 维护区间取两种最值,区间加,求区间两种历史最值,区间最小值. 自己的写法调了一个晚上+一个上午+一个下午+一个晚上并没有调出来,90" role="prese ...

  3. uoj169:元旦老人与数列

    题意:http://uoj.ac/problem/169 sol  :线段树..........蜜汁TLE了一个点,不管了..... 代码抄snowMyDream的,orz........... 线段 ...

  4. ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(线段树)

    题目链接:https://nanti.jisuanke.com/t/30996 中文题目: 在喝茶的过程中,公主,除其他外,问为什么这样一个善良可爱的龙在城堡里被监禁Lpl?龙神秘地笑了笑,回答说这是 ...

  5. UOJ.52.[UR #4]元旦激光炮(交互 思路)

    题目链接 \(Description\) 交互库中有三个排好序的,长度分别为\(n_a,n_b,n_c\)的数组\(a,b,c\).你需要求出所有元素中第\(k\)小的数.你可以调用至多\(100\) ...

  6. UOJ169. 【UR #11】元旦老人与数列

    传送门 考虑用 \(segment~tree~beats\) 那一套理论,维护区间最小值 \(mn\) 和严格次小值 \(se\) 那么可以直接 \(mlog^2n\) 维护前三个操作 考虑维护历史最 ...

  7. 【UOJ#169】元旦老人与数列

    论文题. 考虑到这题的维护和区间操作是反向的,也就是说无法像V那题快速的合并标记. 我们知道,一个区间的最小值和其他值是可以分开来维护的,因为如果一个区间被整体覆盖,那么最小值始终是最小值. 对于被覆 ...

  8. 入职第一个项目bug总结-2018/07/28

    此项目是正式入职后的第一个项目,可能各种原因重重,导致测试提出了如此多的bug,关于那些因为需求不清楚而导致的就不说了,bug总结如下: 一.ElementUI table组件出现横向滚动条 原因:因 ...

  9. 【2018.07.28】(字符串/回文串)学习Manacher算法小记

    主要是应用在回文串啦,原理也理解了老半天,如果没有图片的话,我也看不太懂它的原理 学习的灵感来源来自于:https://segmentfault.com/a/1190000008484167 /* 最 ...

随机推荐

  1. FMX TListView 搜索 Search

    FMX,FireMonkey,平台框架下TListView控件搜索.过滤. 查找功能确实强大!! 设置SearchVisibe属性为true,就自动显示搜索框,输入文字,就开始检索了,不用写一行代码! ...

  2. c++builder XE6 线程 tthread

    thread TThread class TSleepFunc : public TCppInterfacedObject<TProc> { public: TSleepFunc(TFor ...

  3. JSON解析工具比较,主要GSON和FastJSON

    JSON解析工具比较,主要GSON和FastJSON 一 .各个JSON技术的简介和优劣 1.json-lib json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确 ...

  4. 字典(dictionary) 的基本操作

    info = { ’stu1101‘ : ’xiaoming’, ‘stu1102 : xiahong‘, ’stu1103 : ‘xiaozhi', } 1. 字典的获取 info.get('stu ...

  5. 切换svn登录账户

    右键-->TortoiseSVN-->设置 找到:点击已缓存数据 在认证数据一栏点击:清空

  6. 如何选择 SQL Server 数据库跟操作系统版本

    简介: 今天老大提需求, 需要一台 Windows 服务器, 需要安装最新版的 SQL Server 数据库.额, 上次搞 Windows 服务器还是4年前的事. 一.啥也没查, 直接下载操作系统.做 ...

  7. nstall neovim on Ubuntu 16.04

    https://neovim.io/ To install NeoVim on Ubuntu, run 1 2 3 sudo add-apt-repository ppa:neovim-ppa/sta ...

  8. TensorFlow RNN MNIST字符识别演示快速了解TF RNN核心框架

    TensorFlow RNN MNIST字符识别演示快速了解TF RNN核心框架 http://blog.sina.com.cn/s/blog_4b0020f30102wv4l.html

  9. js中常见的创建对象的方法

    前两天好好的把高程对象那一块又读了下,顺便写点笔记.补一句:代码都测试过了,应该没有问题的.可以直接拿到控制台跑! 1.工厂模式 function person(name, age, job) { v ...

  10. javascript中的二维数组

    要创建一个二位数组我们脑子里第一个出现的就是 var arr=[][]; 但是在javascript这样是会报错的,要在javascrip中创建一个二位数组对象方法如下 方法一     直接把数组写出 ...