【学习笔记/模板】吉司机线段树

吉司机线段树

前言

吉司机线段树,是吉如一老师在国家队论文中提出的一种线段树,可以实现区间修改取 \(\min/\max\) 和记录历史最大/最小值的操作。

例题:

P6242 【模板】线段树 3

这道例题基本上涵盖了吉司机线段树的经典操作,其 \(B\) 数组其实就是记录了 \(A\) 数组的历史最大值。

所以五个操作就是:

操作 概述
1 区间加法
2 区间修改为最小值
3 区间求和
4 区间查询最大值
5 区间查询历史最大值

作为进阶版本的线段树,其节点维护的值也有所增加。我们先介绍一遍他们,作用且按下不表。

struct Tree{
    int l, r;
    LL sum;
    LL max_st, max_nd, max_his;
    LL num_max;
    LL lazy_st, lazy_sth, lazy_nd, lazy_ndh;
}tr[MAXN << 2];

\(l\)\(r\):区间左右端点;
\(sum\):区间所有元素的和;
\(maxst\):区间的最大值;
\(maxnd\):区间的严格次大值
\(maxhis\):区间的历史最大值;
\(nummax\):区间最大值出现的次数;
\(lazyst\):区间最大值的加减标记;
\(lazysth\):区间历史最大值的加减标记;
\(lazynd\):区间非最大值的加减标记;
\(lazyndh\):区间非历史最大值的加减标记;

这里,大家可以巧妙的运用 define,不然就会像某个喜欢把变量名起的贼TM长还不用 define 的神必一样写出一份 \(6.12KB\) 的极为难调的代码。

然后,我们分模块来实现这棵线段树。

建树

建树其实没什么区别,只是叶子节点上没有第二个元素,区间严格次大值赋为 \(-INF\) 即可(代表区间严格次大值为空,方便以后更新)。

void Build(int rt, int l, int r){
    tr[rt].l = l;
    tr[rt].r = r;

    if(l == r){
        tr[rt].sum = tr[rt].max_st = tr[rt].max_his = num[l];
        tr[rt].num_max = 1;
        tr[rt].max_nd = -INF;

        return;
    }

    int mid = (l + r) >> 1;
    Build(lson(rt), l, mid);
    Build(rson(rt), mid + 1, r);

    Pushup(rt);
}

pushup

pushup 会更新当前节点的 \(sum,maxst,maxnd,maxhis,nummax\)

\(sum\) 是左右儿子的加和。
\(maxst,maxhis\) 肯定是左右儿子中大的那一个。

\(nummax\) 需要分类讨论:

  • 左右儿子的 \(maxst\) 相同时,\(nummax\) 就是左右儿子的 \(nummax\) 的和;

  • 否则,\(nummax\) 是左右儿子中 \(maxst\) 大的那个的 \(nummax\)

\(maxnd\) 同理:

  • 左右儿子的 \(maxst\) 相同时,\(maxnd\) 就是左右儿子的 \(maxnd\) 中大的那个;

  • 否则,\(maxnd\)\(maxst\) 小的那个儿子的 \(maxst\)\(maxst\) 大的那个儿子的 \(maxnd\) 中大的那个。

inline void Pushup(int rt){
    tr[rt].sum = tr[lson(rt)].sum + tr[rson(rt)].sum;
    tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
    tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);

    if(tr[lson(rt)].max_st == tr[rson(rt)].max_st){
        tr[rt].num_max = tr[lson(rt)].num_max + tr[rson(rt)].num_max;
        tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_nd);
    }
    else if(tr[lson(rt)].max_st > tr[rson(rt)].max_st){
        tr[rt].num_max = tr[lson(rt)].num_max;
        tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_st);
    }
    else if(tr[lson(rt)].max_st < tr[rson(rt)].max_st){
        tr[rt].num_max = tr[rson(rt)].num_max;
        tr[rt].max_nd = max(tr[lson(rt)].max_st, tr[rson(rt)].max_nd);
    }
}

你不写 define 现在行宽都TM成什么样了。

pushdown

额,这里算是个难点吧,方便理解同时减少码量(你还好意思说减少码量),我们把懒标记的下方拆成两个函数 ModifyPushdown

先看 Modify

\(valst\):区间最大值加上的数;
\(valsth\):区间历史最大值加上的数;
\(valnd\):区间非最大值加上的数;
\(valndh\):区间历史非最大值加上的数。

变量名怎么又怎么长!

  • 更新 \(sum\),把区间最大值的个数乘上 \(valst\),其他的数的个数乘上 \(valnd\),他们的和即为 \(sum\) 的新增部分。

  • 更新 \(maxhis\),此时,未更新的 \(maxst\) 也成为了“历史”,所以 \(maxhis\)\(maxhis\)\(maxst + valsth\) 的最大值。

  • 更新 \(maxst\),直接加上 \(val_st\) 就行了。

  • 更新 \(maxnd\),如果这个区间有 \(maxnd\),即 \(maxnd ≠ -INF\),加上 \(valnd\)

之后我们更新懒标记,(捏麻麻地变量名起这么长写博客都难写)。

  • 更新 \(lazysth\),此时,为更新的 \(lazyst\) 也和 \(maxst\) 一样,成为了“历史”,\(lazysth\) 的值也就是 \(lazysth\)\(lazyst + valsth\) 的最大值;

  • 更新 \(lazyst\),直接加;

  • 更新 \(lazyndh\)\(lazyndh\)\(lazynd + valndh\) 的最大值,理由同 \(lazysth\)

  • 更新 \(lazyndh\),直接加。

值得注意的是更新的顺序问题,先更新历史最值,在更新当前的最值。

inline void Modify(int rt, LL val_st, LL val_sth, LL val_nd, LL val_ndh){
    tr[rt].sum += (tr[rt].num_max * val_st + (tr[rt].r - tr[rt].l + 1 - tr[rt].num_max) * val_nd);
    tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth);
    tr[rt].max_st += val_st;

    if(tr[rt].max_nd != -INF) tr[rt].max_nd += val_nd;

    tr[rt].lazy_sth = max(tr[rt].lazy_sth, tr[rt].lazy_st + val_sth);
    tr[rt].lazy_st += val_st;
    tr[rt].lazy_ndh = max(tr[rt].lazy_ndh, tr[rt].lazy_nd + val_ndh);
    tr[rt].lazy_nd += val_nd;
}

更TM的宽了艹。

然后是 Pushdown

当一个儿子的最大值等于当前区间的最大值时,这个子节点就要以更新最大值来更新。反之则以非最大值来更新。

值得注意的是,不能每次在判断时比较两个子节点的 \(maxst\) 的大小,要提前记录,因为有一个子节点已经被先行更新了。

inline void Pushdown(int rt){
    int maxn = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);

    if(tr[lson(rt)].max_st == maxn)
        Modify(lson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
    else Modify(lson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);

    if(tr[rson(rt)].max_st == maxn)
        Modify(rson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
    else Modify(rson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);

    tr[rt].lazy_st = 0, tr[rt].lazy_sth = 0, tr[rt].lazy_nd = 0, tr[rt].lazy_ndh = 0;
}

Update_Add

对应操作 \(1\),把所有数都加上 \(k\) 的话直接 Modify(rt, k, k, k, k) 就行了。

void Update_Add(int rt, int l, int r, LL val){
    if(tr[rt].l >= l && tr[rt].r <= r){
        Modify(rt, val, val, val, val);
        return;
    }

    Pushdown(rt);

    int mid = (tr[rt].l + tr[rt].r) >> 1;
    if(l <= mid) Update_Add(lson(rt), l, r, val);
    if(r > mid) Update_Add(rson(rt), l, r, val);

    Pushup(rt);
}

Update_Min

对应操作 \(2\),将区间 \([l, r]\) 中的 \(A_{i}\) 都变成 \(\min (A_{i},v)\)

显然,当区间的 \(maxst ≥ v\) 的话,就可以直接 return 润了,然后继续递归?

然后就假掉了,当 \(v\) 很小的时候,复杂度直接卡满,还记得我们维护的区间严格次大值吗,这时候他就排上用场了。

我们找到一个 \(maxst > v\)\(maxnd < v\) 的区间,然后只用更改区间的最大值就行了,取 \(\min\) 的操作可以传化成减法。

void Update_Min(int rt, int l, int r, LL val){
    if(tr[rt].max_st <= val) return;

    if(tr[rt].l >= l && tr[rt].r <= r && tr[rt].max_nd < val){
        Modify(rt, val - tr[rt].max_st, val - tr[rt].max_st, 0, 0);
        return;
    }

    Pushdown(rt);

    int mid = (tr[rt].l + tr[rt].r) >> 1;
    if(l <= mid) Update_Min(lson(rt), l, r, val);
    if(r > mid) Update_Min(rson(rt), l, r, val);

    Pushup(rt);
}

剩下的查询和普通线段树一样,不用讲,直接给代码吧。

LL Query_Sum(int rt, int l, int r){
    if(tr[rt].l >= l && tr[rt].r <= r)
        return tr[rt].sum;
        
    Pushdown(rt);

    LL ans = 0;
    int mid = (tr[rt].l + tr[rt].r) >> 1;
    if(l <= mid) ans += Query_Sum(lson(rt), l, r);
    if(r > mid) ans += Query_Sum(rson(rt), l, r);

    return ans;
}

LL Query_Max(int rt, int l, int r){
    if(tr[rt].l >= l && tr[rt].r <= r)
        return tr[rt].max_st;
        
    Pushdown(rt);

    LL ans = -INF;
    int mid = (tr[rt].l + tr[rt].r) >> 1;
    if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
    if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));

    return ans;
}

LL Query_His(int rt, int l, int r){
    if(tr[rt].l >= l && tr[rt].r <= r)
        return tr[rt].max_his;

    Pushdown(rt);

    LL ans = -INF;
    int mid = (tr[rt].l + tr[rt].r) >> 1;
    if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r));
    if(r > mid) ans = max(ans, Query_His(rson(rt), l, r));

    return ans;
}

Code

#include<cstdio>
#include<algorithm>

#define LL long long

using namespace std;

const LL INF = 1e18;
const int MAXN = 5e5 + 10;
int n, m;
LL num[MAXN];

inline LL read(){
    LL x = 0, f = 1;
    char c = getchar();

    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}

struct Segment_Tree{
    struct Tree{
        int l, r;
        LL sum;
        LL max_st, max_nd, max_his;
        LL num_max;
        LL lazy_st, lazy_sth, lazy_nd, lazy_ndh;
    }tr[MAXN << 2];

    inline int lson(int rt){
        return rt << 1;
    }

    inline int rson(int rt){
        return rt << 1 | 1;
    }

    inline void Pushup(int rt){
        tr[rt].sum = tr[lson(rt)].sum + tr[rson(rt)].sum;
        tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
        tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);

        if(tr[lson(rt)].max_st == tr[rson(rt)].max_st){
            tr[rt].num_max = tr[lson(rt)].num_max + tr[rson(rt)].num_max;
            tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_nd);
        }
        else if(tr[lson(rt)].max_st > tr[rson(rt)].max_st){
            tr[rt].num_max = tr[lson(rt)].num_max;
            tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_st);
        }
        else if(tr[lson(rt)].max_st < tr[rson(rt)].max_st){
            tr[rt].num_max = tr[rson(rt)].num_max;
            tr[rt].max_nd = max(tr[lson(rt)].max_st, tr[rson(rt)].max_nd);
        }
    }

    void Build(int rt, int l, int r){
        tr[rt].l = l;
        tr[rt].r = r;

        if(l == r){
            tr[rt].sum = tr[rt].max_st = tr[rt].max_his = num[l];
            tr[rt].num_max = 1;
            tr[rt].max_nd = -INF;

            return;
        }

        int mid = (l + r) >> 1;
        Build(lson(rt), l, mid);
        Build(rson(rt), mid + 1, r);

        Pushup(rt);
    }

    inline void Modify(int rt, LL val_st, LL val_sth, LL val_nd, LL val_ndh){
        tr[rt].sum += (tr[rt].num_max * val_st + (tr[rt].r - tr[rt].l + 1 - tr[rt].num_max) * val_nd);
        tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth);
        tr[rt].max_st += val_st;

        if(tr[rt].max_nd != -INF) tr[rt].max_nd += val_nd;

        tr[rt].lazy_sth = max(tr[rt].lazy_sth, tr[rt].lazy_st + val_sth);
        tr[rt].lazy_st += val_st;
        tr[rt].lazy_ndh = max(tr[rt].lazy_ndh, tr[rt].lazy_nd + val_ndh);
        tr[rt].lazy_nd += val_nd;
    }

    inline void Pushdown(int rt){
        int maxn = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);

        if(tr[lson(rt)].max_st == maxn)
            Modify(lson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
        else Modify(lson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);

        if(tr[rson(rt)].max_st == maxn)
            Modify(rson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
        else Modify(rson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);

        tr[rt].lazy_st = 0, tr[rt].lazy_sth = 0, tr[rt].lazy_nd = 0, tr[rt].lazy_ndh = 0;
    }

    void Update_Add(int rt, int l, int r, LL val){
        if(tr[rt].l >= l && tr[rt].r <= r){
            Modify(rt, val, val, val, val);
            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Add(lson(rt), l, r, val);
        if(r > mid) Update_Add(rson(rt), l, r, val);

        Pushup(rt);
    }

    void Update_Min(int rt, int l, int r, LL val){
        if(tr[rt].max_st <= val) return;

        if(tr[rt].l >= l && tr[rt].r <= r && tr[rt].max_nd < val){
            Modify(rt, val - tr[rt].max_st, val - tr[rt].max_st, 0, 0);
            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Min(lson(rt), l, r, val);
        if(r > mid) Update_Min(rson(rt), l, r, val);

        Pushup(rt);
    }

    LL Query_Sum(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r)
            return tr[rt].sum;
        
        Pushdown(rt);

        LL ans = 0;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans += Query_Sum(lson(rt), l, r);
        if(r > mid) ans += Query_Sum(rson(rt), l, r);

        return ans;
    }

    LL Query_Max(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r)
            return tr[rt].max_st;
        
        Pushdown(rt);

        LL ans = -INF;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
        if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));

        return ans;
    }

    LL Query_His(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r)
            return tr[rt].max_his;

        Pushdown(rt);

        LL ans = -INF;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r));
        if(r > mid) ans = max(ans, Query_His(rson(rt), l, r));

        return ans;
    }
}S;

int main(){
    n = read(), m = read();
    for(register int i = 1; i <= n; i++)
        num[i] = read();
    
    S.Build(1, 1, n);

    for(register int i = 1; i <= m; i++){
        int opt;
        opt = read();

        if(opt == 1){
            int l, r, k;
            l = read(), r = read(), k = read();
            S.Update_Add(1, l, r, k);
        }
        else if(opt == 2){
            int l, r, v;
            l = read(), r = read(), v = read();
            S.Update_Min(1, l, r, v);
        }
        else if(opt == 3){
            int l, r;
            l = read(), r = read();
            printf("%lld\n", S.Query_Sum(1, l, r));
        }
        else if(opt == 4){
            int l, r;
            l = read(), r = read();
            printf("%lld\n", S.Query_Max(1, l, r));
        }
        else{
            int l, r;
            l = read(), r = read();
            printf("%lld\n", S.Query_His(1, l, r));
        }
    }

    return 0;
}

你怎么TMD变量名这么长还就是不写宏定义啊

image

P4314 CPU 监控

Code

#include<cstdio>
#include<algorithm>

using namespace std;

const int MAXN = 1e5 + 10;
const int INF = 2147483647;
int t, e;
int num[MAXN];

inline int read(){
    int x = 0, f = 1;
    char c = getchar();

    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}

struct Segment_Tree{
    struct Tree{
        int l, r;
        int max_st, max_his; //区间最大值,历史区间最大值
        int lazy_st_add, lazy_sth_add; //区间加的懒标记,区间加的历史最大值的懒标记
        int lazy_st_cov, lazy_sth_cov; //区间覆盖的懒标记,区间的历史最大值的最大覆盖的懒标记 

        Tree(){
            lazy_st_add = lazy_sth_add = 0;
            lazy_st_cov = lazy_sth_cov = -INF;
        }
    }tr[MAXN << 2];

    inline int lson(int rt){
        return rt << 1;
    }

    inline int rson(int rt){
        return rt << 1 | 1;
    }

    inline void Pushup(int rt){
        tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
        tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);
    }

    void Build(int rt, int l, int r){
        tr[rt].l = l;
        tr[rt].r = r;

        if(l == r){
            tr[rt].max_st = tr[rt].max_his = num[l];
            return;
        }

        int mid = (l + r) >> 1;
        Build(lson(rt), l, mid);
        Build(rson(rt), mid + 1, r);

        Pushup(rt);
    }

    inline void Modify_Add(int rt, int val_st, int val_sth){
        tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth);
        tr[rt].max_st += val_st;

        if(tr[rt].lazy_st_cov == -INF){
            tr[rt].lazy_sth_add = max(tr[rt].lazy_sth_add, tr[rt].lazy_st_add + val_sth);
            tr[rt].lazy_st_add += val_st;
        }
        else{
            tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, tr[rt].lazy_st_cov + val_sth);
            tr[rt].lazy_st_cov += val_st;
        }
    }

    inline void Modify_Cov(int rt, int val_st, int val_sth){
        tr[rt].max_st = val_st;
        tr[rt].max_his = max(tr[rt].max_his, val_sth);
        tr[rt].lazy_st_cov = val_st;
        tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, val_sth);
    }

    inline void Pushdown(int rt){
        if(tr[rt].lazy_st_add || tr[rt].lazy_sth_add){
            Modify_Add(lson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add);
            Modify_Add(rson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add);
            tr[rt].lazy_st_add = tr[rt].lazy_sth_add = 0;
        }

        if(tr[rt].lazy_st_cov != -INF || tr[rt].lazy_sth_cov != -INF){
            Modify_Cov(lson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov);
            Modify_Cov(rson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov);
            tr[rt].lazy_st_cov = tr[rt].lazy_sth_cov = -INF;
        }
    }

    void Update_Add(int rt, int l, int r, int val){
        if(tr[rt].l >= l && tr[rt].r <= r){
            Modify_Add(rt, val, val);
            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Add(lson(rt), l, r, val);
        if(r > mid) Update_Add(rson(rt), l, r, val);

        Pushup(rt);
    }

    void Update_Cov(int rt, int l, int r, int val){
        if(tr[rt].l >= l && tr[rt].r <= r){
            Modify_Cov(rt, val, val);
            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Cov(lson(rt), l, r, val);
        if(r > mid) Update_Cov(rson(rt), l, r, val);

        Pushup(rt);        
    }

    int Query_Max(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r)
            return tr[rt].max_st;
        
        Pushdown(rt);

        int ans = -INF;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
        if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));

        return ans;
    }

    int Query_His(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r)
            return tr[rt].max_his;
        
        Pushdown(rt);

        int ans = -INF;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r));
        if(r > mid) ans = max(ans, Query_His(rson(rt), l, r));

        return ans;
    }
}S;

int main(){
    t = read();
    for(register int i = 1; i <= t; i++)
        num[i] = read();
    
    S.Build(1, 1, t);

    e = read();
    for(register int i = 1; i <= e; i++){
        char opt[5];
        scanf("%s", opt + 1);

        if(opt[1] == 'Q'){
            int l, r;
            l = read(), r = read();
            printf("%d\n", S.Query_Max(1, l, r));
        }
        else if(opt[1] == 'A'){
            int l, r;
            l = read(), r = read();
            printf("%d\n", S.Query_His(1, l, r));
        }
        else if(opt[1] == 'P'){
            int l, r, v;
            l = read(), r = read(), v = read();
            S.Update_Add(1, l, r, v);
        }
        else if(opt[1] == 'C'){
            int l, r, v;
            l = read(), r = read(), v = read();
            S.Update_Cov(1, l, r, v);
        }
    }

    return 0;
}

你TM怎么还是不写宏定义啊。

image

update at 2022.9.25

Silver_Ash嫌我代码太长,所以提供一个(他喜欢的)压行的。

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const LL INF = 1e18; const int MAXN = 5e5 + 10;
int n, m; LL num[MAXN];
inline LL read(){
    LL x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9' ) {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
    return x * f;
}
struct Segment_Tree{
    struct Tree {int l, r; LL sum, max_st, max_nd, max_his, num_max, lazy_st, lazy_sth, lazy_nd, lazy_ndh;}tr[MAXN << 2];
    inline int lson(int rt) {return rt << 1;}
    inline int rson(int rt) {return rt << 1 | 1;}
    inline void Pushup(int rt){
        tr[rt].sum = tr[lson(rt)].sum + tr[rson(rt)].sum; tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st); tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);
        if(tr[lson(rt)].max_st == tr[rson(rt)].max_st) {tr[rt].num_max = tr[lson(rt)].num_max + tr[rson(rt)].num_max; tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_nd);}
        else if(tr[lson(rt)].max_st > tr[rson(rt)].max_st) {tr[rt].num_max = tr[lson(rt)].num_max; tr[rt].max_nd = max(tr[lson(rt)].max_nd, tr[rson(rt)].max_st);}
        else if(tr[lson(rt)].max_st < tr[rson(rt)].max_st) {tr[rt].num_max = tr[rson(rt)].num_max; tr[rt].max_nd = max(tr[lson(rt)].max_st, tr[rson(rt)].max_nd);}
    }
    void Build(int rt, int l, int r){
        tr[rt].l = l; tr[rt].r = r;
        if(l == r) {tr[rt].sum = tr[rt].max_st = tr[rt].max_his = num[l]; tr[rt].num_max = 1; tr[rt].max_nd = -INF; return;}
        int mid = (l + r) >> 1; Build(lson(rt), l, mid); Build(rson(rt), mid + 1, r); Pushup(rt);
    }
    inline void Modify(int rt, LL val_st, LL val_sth, LL val_nd, LL val_ndh){
        tr[rt].sum += (tr[rt].num_max * val_st + (tr[rt].r - tr[rt].l + 1 - tr[rt].num_max) * val_nd);
        tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth); tr[rt].max_st += val_st;
        if(tr[rt].max_nd != -INF) tr[rt].max_nd += val_nd;
        tr[rt].lazy_sth = max(tr[rt].lazy_sth, tr[rt].lazy_st + val_sth); tr[rt].lazy_st += val_st;
        tr[rt].lazy_ndh = max(tr[rt].lazy_ndh, tr[rt].lazy_nd + val_ndh); tr[rt].lazy_nd += val_nd;
    }
    inline void Pushdown(int rt){
        int maxn = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st);
        if(tr[lson(rt)].max_st == maxn) Modify(lson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
        else Modify(lson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
        if(tr[rson(rt)].max_st == maxn) Modify(rson(rt), tr[rt].lazy_st, tr[rt].lazy_sth, tr[rt].lazy_nd, tr[rt].lazy_ndh);
        else Modify(rson(rt), tr[rt].lazy_nd, tr[rt].lazy_ndh, tr[rt].lazy_nd, tr[rt].lazy_ndh);
        tr[rt].lazy_st = 0, tr[rt].lazy_sth = 0, tr[rt].lazy_nd = 0, tr[rt].lazy_ndh = 0;
    }
    void Update_Add(int rt, int l, int r, LL val){
        if(tr[rt].l >= l && tr[rt].r <= r) {Modify(rt, val, val, val, val); return;}
        Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Add(lson(rt), l, r, val); if(r > mid) Update_Add(rson(rt), l, r, val); Pushup(rt);
    }
    void Update_Min(int rt, int l, int r, LL val){
        if(tr[rt].max_st <= val) return;
        if(tr[rt].l >= l && tr[rt].r <= r && tr[rt].max_nd < val) {Modify(rt, val - tr[rt].max_st, val - tr[rt].max_st, 0, 0); return;}
        Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Min(lson(rt), l, r, val); if(r > mid) Update_Min(rson(rt), l, r, val); Pushup(rt);
    }
    LL Query_Sum(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].sum;
        Pushdown(rt); LL ans = 0; int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans += Query_Sum(lson(rt), l, r); if(r > mid) ans += Query_Sum(rson(rt), l, r); return ans;
    }
    LL Query_Max(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_st;
        Pushdown(rt); LL ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r)); return ans;
    }
    LL Query_His(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_his;
        Pushdown(rt); LL ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_His(rson(rt), l, r)); return ans;
    }
}S;
int main(){
    n = read(), m = read();
    for(register int i = 1; i <= n; i++) num[i] = read();
    S.Build(1, 1, n);
    for(register int i = 1; i <= m; i++){
        int opt = read();
        if(opt == 1) {int l, r, k; l = read(), r = read(), k = read(); S.Update_Add(1, l, r, k);}
        else if(opt == 2) {int l, r, v; l = read(), r = read(), v = read(); S.Update_Min(1, l, r, v);}
        else if(opt == 3) {int l, r; l = read(), r = read(); printf("%lld\n", S.Query_Sum(1, l, r));}
        else if(opt == 4) {int l, r; l = read(), r = read(); printf("%lld\n", S.Query_Max(1, l, r));}
        else {int l, r; l = read(), r = read(); printf("%lld\n", S.Query_His(1, l, r));}
    }
    return 0;
}
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 10; const int INF = 2147483647;
int t, e, num[MAXN];
inline int read(){
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
    return x * f;
}
struct Segment_Tree{
    struct Tree{
        int l, r; int max_st, max_his, lazy_st_add, lazy_sth_add, lazy_st_cov, lazy_sth_cov;
        Tree() {lazy_st_add = lazy_sth_add = 0; lazy_st_cov = lazy_sth_cov = -INF;}
    }tr[MAXN << 2];
    inline int lson(int rt) {return rt << 1;}
    inline int rson(int rt) {return rt << 1 | 1;}
    inline void Pushup(int rt){ tr[rt].max_st = max(tr[lson(rt)].max_st, tr[rson(rt)].max_st); tr[rt].max_his = max(tr[lson(rt)].max_his, tr[rson(rt)].max_his);}
    void Build(int rt, int l, int r){
        tr[rt].l = l; tr[rt].r = r;
        if(l == r){ tr[rt].max_st = tr[rt].max_his = num[l]; return;}
        int mid = (l + r) >> 1; Build(lson(rt), l, mid); Build(rson(rt), mid + 1, r); Pushup(rt);
    }
    inline void Modify_Add(int rt, int val_st, int val_sth){
        tr[rt].max_his = max(tr[rt].max_his, tr[rt].max_st + val_sth); tr[rt].max_st += val_st;
        if(tr[rt].lazy_st_cov == -INF) {tr[rt].lazy_sth_add = max(tr[rt].lazy_sth_add, tr[rt].lazy_st_add + val_sth); tr[rt].lazy_st_add += val_st;}
        else {tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, tr[rt].lazy_st_cov + val_sth); tr[rt].lazy_st_cov += val_st;}
    }
    inline void Modify_Cov(int rt, int val_st, int val_sth){
        tr[rt].max_st = val_st; tr[rt].max_his = max(tr[rt].max_his, val_sth);
        tr[rt].lazy_st_cov = val_st; tr[rt].lazy_sth_cov = max(tr[rt].lazy_sth_cov, val_sth);
    }
    inline void Pushdown(int rt){
        if(tr[rt].lazy_st_add || tr[rt].lazy_sth_add){
            Modify_Add(lson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add); Modify_Add(rson(rt), tr[rt].lazy_st_add, tr[rt].lazy_sth_add);
            tr[rt].lazy_st_add = tr[rt].lazy_sth_add = 0;
        }
        if(tr[rt].lazy_st_cov != -INF || tr[rt].lazy_sth_cov != -INF){
            Modify_Cov(lson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov); Modify_Cov(rson(rt), tr[rt].lazy_st_cov, tr[rt].lazy_sth_cov);
            tr[rt].lazy_st_cov = tr[rt].lazy_sth_cov = -INF;
        }
    }
    void Update_Add(int rt, int l, int r, int val){
        if(tr[rt].l >= l && tr[rt].r <= r) {Modify_Add(rt, val, val); return;}
        Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Add(lson(rt), l, r, val); if(r > mid) Update_Add(rson(rt), l, r, val); Pushup(rt);
    }
    void Update_Cov(int rt, int l, int r, int val){
        if(tr[rt].l >= l && tr[rt].r <= r) {Modify_Cov(rt, val, val); return;}
        Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Cov(lson(rt), l, r, val); if(r > mid) Update_Cov(rson(rt), l, r, val); Pushup(rt);        
    }
    int Query_Max(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_st;
        Pushdown(rt); int ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r)); return ans;
    }
    int Query_His(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max_his;
        Pushdown(rt); int ans = -INF; int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_His(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_His(rson(rt), l, r)); return ans;
    }
}S;
int main(){
    t = read(); for(register int i = 1; i <= t; i++) num[i] = read();
    S.Build(1, 1, t); e = read();
    for(register int i = 1; i <= e; i++){
        char opt[5]; scanf("%s", opt + 1);
        if(opt[1] == 'Q') {int l, r; l = read(), r = read(); printf("%d\n", S.Query_Max(1, l, r));}
        else if(opt[1] == 'A') {int l, r; l = read(), r = read(); printf("%d\n", S.Query_His(1, l, r));}
        else if(opt[1] == 'P') {int l, r, v; l = read(), r = read(), v = read(); S.Update_Add(1, l, r, v);}
        else if(opt[1] == 'C') {int l, r, v; l = read(), r = read(), v = read(); S.Update_Cov(1, l, r, v);}
    }
    return 0;
}

就离谱,我把换行和缩进删了码量直接减少2KB

posted @ 2022-09-22 21:43  TSTYFST  阅读(564)  评论(4编辑  收藏  举报