SegmentTreeBeats

节拍线段树

按照模板题来说,应该有两个部分,一个是维护区间历史最值,一个是势能地区间取 \(max\)\(min\) 求区间和。

区间取 \(max\)\(min\) 求区间和

HDU 5306 Gorgeous Sequence

挂的是原题没有多测的版本。

如果没有区间求和显然是好做的。

我们考虑将元素划分为两类,一种是最大值,一种是非最大值。我们用结构体封装起来这两类数的集合,最大值是 \(mx\) 非最大值为 \(se\)。我们考虑直接线段树维护,我们令 \(\text{mx}(mx_i)\)\(\text{mx}(se_i)\) 表示两个集合中的最大值,对于节点 \(i\),如果说 \(\text{mx}(mx_i) \le x\) 显然不会有贡献;对于 \(x \in (\text{mx}(se_i), \text{mx}(mx_i))\),显然我们可以直接修改,计集合元素数量的为 \(\text{cnt}(mx_i)\),那么将区间和 \(sum_i \gets sum + \text{cnt}(mx_i) \times (x - \text{mx}(mx_i))\) 再将 \(\text{mx}(mx_i) \gets x\) 即可;对于 \(x \le \text{mx}(se_i)\) 我们直接暴力递归到儿子去算然后 push_up() 上来即可。push_down() 也是一样的。对于 push_up(),分讨三类情况即可,具体细节可以看代码,应该是比较好理解的。

code
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define int int
#define ll long long
#define usd unsigned
#define el putchar('\n')
#define lowbit(x) (x & (-x))
#define AC return 
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <int, int>
il char gc() { char c; while((c = getchar()) <= ' ') ; return c; }
il int rd() {
	char c; int x, f = 1;
	while(!isdigit(c = getchar())) if(c == '-') f *= -1;
	x = c ^ 48;
	while(isdigit(c = getchar())) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}
void ACehomoxue();
signed main() {
	// freopen(".in", "r", stdin);
	// freopen(".out", "w", stdout);
	int t = 1;
	while(t--) ACehomoxue();
	AK;
}
const int mod = 998244353, maxn = 1e6 + 18;

class xds {
    struct ele {
        int val, \text{cnt};
        ele(int v = 0, int c = 0) { val = v, \text{cnt} = c; }
        void clr() { val = -1, \text{cnt} = 0; }
        void upd(ele a) {
            if(a.val > val) val = a.val, \text{cnt} = a.\text{cnt};
            else if(a.val == val) \text{cnt} += a.\text{cnt};
        }
    } ;
    struct tree {
        int l, r; ll tag, sum;
        ele mx, se;
    } t[maxn << 2];
    void push_up(int i) {
        t[i].sum = t[i * 2].sum + t[i * 2 + 1].sum;
        t[i].mx.clr(), t[i].se.clr();
        if(t[i * 2].mx.val > t[i * 2 + 1].mx.val) {
            t[i].mx.upd(t[i * 2].mx);
            t[i].se.upd(t[i * 2].se);
            t[i].se.upd(t[i * 2 + 1].mx);
        } else if(t[i * 2].mx.val < t[i * 2 + 1].mx.val) {
            t[i].mx.upd(t[i * 2 + 1].mx);
            t[i].se.upd(t[i * 2 + 1].se);
            t[i].se.upd(t[i * 2].mx);
        } else {
            t[i].mx.upd(t[i * 2].mx);
            t[i].mx.upd(t[i * 2 + 1].mx);
            t[i].se.upd(t[i * 2].se);
            t[i].se.upd(t[i * 2 + 1].se);
        }
    }
    void mdf(int i, ll k) {
        if(k >= t[i].mx.val) AC;
        t[i].sum -= 1ll * t[i].mx.\text{cnt} * t[i].mx.val;
        t[i].mx.val = k;
        t[i].sum += 1ll * t[i].mx.\text{cnt} * t[i].mx.val;
        t[i].tag = min(t[i].tag, k);
    }
    void push_down(int i) { if(t[i].tag < 1e14) mdf(i * 2, t[i].tag), mdf(i * 2 + 1, t[i].tag); t[i].tag = 1e18; }
public:
    void build(int i, int l, int r, int *a) {
        t[i].l = l, t[i].r = r, t[i].se.clr(), t[i].mx.clr(), t[i].tag = 1e18;
        if(l == r) {
            t[i].mx.val = a[l];
            t[i].mx.\text{cnt} = 1;
            t[i].sum = a[l];
            AC;
        }
        int mid = l + r >> 1;
        build(i * 2, l, mid, a);
        build(i * 2 + 1, mid + 1, r, a);
        push_up(i);
    }
    void updata(int i, int l, int r, int x) {
        if(t[i].l >= l && t[i].r <= r) {
            if(t[i].se.val >= x) {
                push_down(i);
                updata(i * 2, l, r, x);
                updata(i * 2 + 1, l, r, x);
                push_up(i);
                AC;
            }
            mdf(i, x);
            AC;
        }
        push_down(i);
        int mid = t[i].l + t[i].r >> 1;
        if(l <= mid) updata(i * 2, l, r, x);
        if(r > mid) updata(i * 2 + 1, l, r, x);
        push_up(i);
    }
    il int querymx(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].mx.val;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = 0;
        if(l <= mid) res = max(res, querymx(i * 2, l, r));
        if(r > mid) res = max(res, querymx(i * 2 + 1, l, r));
        return res;
    }
    il ll querysum(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].sum;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1; ll res = 0;
        if(l <= mid) res += querysum(i * 2, l, r);
        if(r > mid) res += querysum(i * 2 + 1, l, r);
        return res;
    }
} ds;

int n, q, a[maxn];

void ACehomoxue() {
	n = rd(), q = rd();
    for(int i = 1; i <= n; i++) a[i] = rd();
    ds.build(1, 1, n, a);
    for(int opt; q--; ) {
        opt = rd();
        if(opt == 0) {
            int l = rd(), r = rd(), x = rd();
            ds.updata(1, l, r, x);
        } 
        if(opt == 1) {
            int l = rd(), r = rd();
            cout << ds.querymx(1, l, r);
            el;
        }
        if(opt == 2) {
            int l = rd(), r = rd();
            cout << ds.querysum(1, l, r);
            el;
        }
    }
}

时间复杂度证明

注意到当 \(se_i\) 为空时线段树节点 \(i\) 一定不会继续递归下去,并且经过一次递归后 \(se_i\) 一定为空,那么显然时间复杂度为均摊 \(O(n + n \log n)\)

当加入区间加后的复杂度证明

一次区间加最多让 \(\log ^ 2 n\)\(se_i\) 为空的节点的 \(se_i\) 不为空,那么复杂度应为均摊 \(O(n \log ^ 2 n + n \log n)\) 的。

区间历史最大值

P4314 CPU 监控

这道题的题面翻译成人话就是求区间 \(\max\)、求区间历史 \(\max\)、区间覆盖、区间加。

我们考虑直接线段树维护。我们可以直接维护一个 \(mx_i\) 表示区间最值和 \(ans_i\) 表示历史最值在线段树节点 \(i\) 上,显然考虑如何解决区间修改。区间修改有两类,显然要打标记,由于要求历史最值,我们的标记不妨也弄个历史最值,\(add_i\) 表示加法标记,\(addmx_i\) 表示历史最大加法标记,\(tag_i\)\(tagmx_i\) 同理。

对于下放标记和修改我们可以把其简化成两个函数 mdfadd(i, x, mx)mdftag(i, x, mx)。表示对节点 \(i\) 进行区间加或覆盖多次,其中最后加上或覆盖的值应为 \(x\),最大历史区间加或覆盖为 \(mx\),其实 \(x\) 就是对应了 \(add\)\(tag\)\(mx\) 对应了 \(addmx\)\(tagmx\),对于修改要将区间加或覆盖为 \(k\),那么显然 \(k = mx = x\)

首先考虑 mdfadd(i, x, mx)。分两种,一是 \(i\) 已经有了覆盖标记,方便维护我们可以专门开一个布尔变量 \(ttag_i\),此时 \(i\) 的值应都为 \(tag_i\),那么我们可以把这次修改看作区间赋值为 \(tag_i + x\),那么有更新 \(tagmx_i \gets \max(tagmx_i, tag_i + x)\),且 \(tag_i \gets tag_i + x\),然后更新两个答案 \(ans_i \gets \max(ans_i, tagmx_i)\)\(mx_i \gets mx_i + x\)。二是没有覆盖标记,那么直接加即可,先更新标记有 \(addmx_i \gets \max(addmx_i, add_i + mx)\)\(add_i \gets add_i + x\),然后更新两个答案有 \(mx_i \gets mx_i + x\)\(ans_i \gets \max(ans_i, mx_i + mx)\)

然后考虑 mdftag(i, x, mx)。首先若没有覆盖标记应先下方 \(i\) 的加法标记,否则会丢失信息。然后就简单了,更新标记有 \(tagmx_i \gets \max(tagmx_i, mx)\)\(tag_i \gets x\),然后更新答案有 \(ans_i \gets \max(ans_i, mx)\)\(mx_i \gets x\)

剩下的就比较简单了,难点就是下放标记。做完了,具体细节看代码。

code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el putchar('\n')
#define lowbit(x) (x & (-x))
#define AC return 
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
il char gc() { char c; while((c = getchar()) <= ' ') ; return c; }
il int rd() {
	char c; int x, f = 1;
	while(!isdigit(c = getchar())) if(c == '-') f *= -1;
	x = c ^ 48;
	while(isdigit(c = getchar())) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}
void ACehomoxue();
signed main() {
	srand(time(0));
	// freopen(".in", "r", stdin);
	// freopen(".out", "w", stdout);
	int t = 1;
	// t = rd();
	while(t--) ACehomoxue();
	AK;
}
const int mod = 998244353, maxn = 1e5 + 18;

int n, a[maxn];

class xds {
    struct {
        int l, r, ans, mx, addmx, tagmx, add, tag;
        bool ttag;
    } t[maxn << 2];
    void push_up(int i) {
        t[i].mx = max(t[i * 2].mx, t[i * 2 + 1].mx);
        t[i].ans = max(t[i * 2].ans, t[i * 2 + 1].ans);
    }
    void mdfadd(int i, int x, int mx) {
        if(t[i].ttag) {
            t[i].tagmx = max(t[i].tagmx, t[i].tag + mx);
            t[i].tag += x;
        } else {
            t[i].addmx = max(t[i].addmx, t[i].add + mx);
            t[i].add += x;
        }
        t[i].ans = max(t[i].ans, t[i].mx + mx);
        t[i].mx += x;
    }
    void mdftag(int i, int x, int mx) {
        if(t[i].ttag) {
            t[i].tagmx = max(t[i].tagmx, mx);
            t[i].tag = x;
        } else {
            if(t[i].l != t[i].r) mdfadd(i * 2, t[i].add, t[i].addmx), mdfadd(i * 2 + 1, t[i].add, t[i].addmx), t[i].add = t[i].addmx = 0;
            t[i].ttag = true;
            t[i].tag = x;
            t[i].tagmx = mx;
        }
        t[i].ans = max(t[i].ans, t[i].tagmx);
        t[i].mx = x;
    }
    void push_down(int i) {
        mdfadd(i * 2, t[i].add, t[i].addmx);
        mdfadd(i * 2 + 1, t[i].add, t[i].addmx);
        t[i].add = t[i].addmx = 0;
        if(t[i].ttag) {
            mdftag(i * 2, t[i].tag, t[i].tagmx);
            mdftag(i * 2 + 1, t[i].tag, t[i].tagmx);
            t[i].tag = t[i].ttag = 0;
            t[i].tagmx = -1e18;
        }
    }
public:
    void build(int i, int l, int r) {
        t[i].l = l, t[i].r = r, t[i].ttag = false, t[i].tag = t[i].add = t[i].addmx = 0;
        t[i].ans = t[i].mx = t[i].tagmx = -1e18;
        if(l == r) {
            t[i].mx = t[i].ans = a[l];
            AC;
        }
        int mid = l + r >> 1;
        build(i * 2, l, mid);
        build(i * 2 + 1, mid + 1, r);
        push_up(i);
    }
    void add(int i, int l, int r, int x) {
        if(t[i].l >= l && t[i].r <= r) {
            mdfadd(i, x, x);
            AC;
        }
        push_down(i);
        int mid = t[i].l + t[i].r >> 1;
        if(l <= mid) add(i * 2, l, r, x);
        if(r > mid) add(i * 2 + 1, l, r, x);
        push_up(i);
    }
    void updata(int i, int l, int r, int x) {
        if(t[i].l >= l && t[i].r <= r) {
            mdftag(i, x, x);
            AC;
        }
        push_down(i);
        int mid = t[i].l + t[i].r >> 1;
        if(l <= mid) updata(i * 2, l, r, x);
        if(r > mid) updata(i * 2 + 1, l, r, x);
        push_up(i);
    }
    il int querymx(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].mx;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = -1e18;
        if(l <= mid) res = max(res, querymx(i * 2, l, r));
        if(r > mid) res = max(res, querymx(i * 2 + 1, l, r));
        return res;
    }
    il int queryhis(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].ans;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = -1e18;
        if(l <= mid) res = max(res, queryhis(i * 2, l, r));
        if(r > mid) res = max(res, queryhis(i * 2 + 1, l, r));
        return res;
    }
} ds;

void ACehomoxue() {
	n = rd();
    for(int i = 1; i <= n; i++) a[i] = rd();
    ds.build(1, 1, n);
    for(int q = rd(), l, r; q--; ) {
        char opt = gc();
        l = rd(), r = rd();
        if(opt == 'Q') cout << ds.querymx(1, l, r), el;
        if(opt == 'A') cout << ds.queryhis(1, l, r), el;
        if(opt == 'P') ds.add(1, l, r, rd());
        if(opt == 'C') ds.updata(1, l, r, rd());
    }
}

SP1557 GSS2 - Can you answer these queries II

上一道是例题这一道是应用。

显然扫描线,线段树位置 \(i\) 维护左端点为 \(i\) 的答案。由于每一个只能算一次,设 \(a_i\) 的上一个位置的下标为 \(lst_{a_i}\)(没有为 \(0\)),那么显然这个数会使区间 \([l, i] (l \in (lst_{a_i}, i])\)\(a_i\) 的贡献,那么一直扫一直加,区间 \([l, i]\) 位置的历史最值就应为询问 \([l, i]\) 区间的答案。做完了。

code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el putchar('\n')
#define lowbit(x) (x & (-x))
#define AC return 
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
il char gc() { char c; while((c = getchar()) <= ' ') ; return c; }
il int rd() {
	char c; int x, f = 1;
	while(!isdigit(c = getchar())) if(c == '-') f *= -1;
	x = c ^ 48;
	while(isdigit(c = getchar())) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}
void ACehomoxue();
signed main() {
	srand(time(0));
	// freopen(".in", "r", stdin);
	// freopen(".out", "w", stdout);
	int t = 1;
	// t = rd();
	while(t--) ACehomoxue();
	AK;
}
const int mod = 998244353, maxn = 1e5 + 18;

struct qry {
    int l, id;
} ;
vector <qry> ask[maxn];

class xds {
    struct tree {
        int l, r, add, addmx, ans, mx;
    } t[maxn << 2];
    void push_up(int i) {
        t[i].mx = max(t[i * 2].mx, t[i * 2 + 1].mx);
        t[i].ans = max(t[i * 2].ans, t[i * 2 + 1].ans);
    }
    void mdf(int i, int x, int mx) {
        t[i].addmx = max(t[i].addmx, t[i].add + mx);
        t[i].ans = max(t[i].ans, t[i].mx + mx);
        t[i].mx += x, t[i].add += x;
    }
    void push_down(int i) { mdf(i * 2, t[i].add, t[i].addmx), mdf(i * 2 + 1, t[i].add, t[i].addmx), t[i].add = t[i].addmx = 0; }
public:
    void build(int i, int l, int r) {
        t[i].l = l, t[i].r = r;
        t[i].add = t[i].mx = 0;
        t[i].ans = t[i].addmx = -1e18;
        if(l == r) AC;
        int mid = l + r >> 1;
        build(i * 2, l, mid);
        build(i * 2 + 1, mid + 1, r);
        push_up(i);
    }
    void updata(int i, int l, int r, int x) {
        if(t[i].l >= l && t[i].r <= r) {
            mdf(i, x, x);
            AC;
        }
        push_down(i);
        int mid = t[i].l + t[i].r >> 1;
        if(l <= mid) updata(i * 2, l, r, x);
        if(r > mid) updata(i * 2 + 1, l, r, x);
        push_up(i);
    }
    il int query(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].ans;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = -1e18;
        if(l <= mid) res = max(res, query(i * 2, l, r));
        if(r > mid) res = max(res, query(i * 2 + 1, l, r));
        return res;
    }
} ds;

int n, a[maxn], q, ans[maxn];
map <int, int> lst;

void ACehomoxue() {
	n = rd();
    for(int i = 1; i <= n; i++) a[i] = rd();
    q = rd();
    for(int i = 1, l, r; i <= q; i++) {
        l = rd(), r = rd();
        ask[r].push_back({l, i});
    } 
    ds.build(1, 1, n);
    for(int i = 1; i <= n; i++) {
        ds.updata(1, lst[a[i]] + 1, i, a[i]);
        lst[a[i]] = i;
        for(auto qq : ask[i]) ans[qq.id] = ds.query(1, qq.l, i);
    }
    for(int i = 1; i <= q; i++, el) cout << ans[i] << ' ';
}

区间最值操作、区间历史最值

P6242 【模板】线段树 3(区间最值操作、区间历史最值)

显然融合上面两种操作即可。

线段树直接维护,每个线段树维护集合 \(mx_i\)\(se_i\),由于要维护历史最值,我们对 \(mx_i\)\(se_i\) 分别打标记,分别打 \(add\)\(addmx\) 标记,push_up()push_down() 都分讨分别贡献。这样我们就解决了区间加和查询。那么对于区间取 \(\min\),假设取的 \(\min\)\(x\),对于节点 \(i\)\(\text{mx}(mx_i) \le x\) 显然无影响;对于 \(x \in (\text{mx}(se_i), \text{mx}(mx_i))\),那么我们可以看作对 \(mx_i\) 中元素进行区间加 \(x - \text{mx}(mx_i)\) 而对 \(se_i\) 中元素什么也不做(这也是为什么要分开打标记);剩下的直接递归分治到儿子,我们证明过了这样是均摊 \(O(n \log ^ 2n)\) 的。做完了,具体细节看代码。

code
#include <bits/stdc++.h>
using namespace std;
#define int ll
#define ll long long
#define usd unsigned
#define el putchar('\n')
#define lowbit(x) (x & (-x))
#define AC return 
#define AK return 0
#define YS cout << "YES"
#define NO cout << "NO"
#define Ys cout << "Yes"
#define No cout << "No"
#define ys cout << "yes"
#define no cout << "no"
#define ls(i) ch[i][0]
#define rs(i) ch[i][1]
#define debug(num) cerr << #num << ' ' << num << '\n'
#define void inline void
#define il inline
#define Mod(x) (((x) % mod + mod) % mod)
#define pii pair <int, int>
#define pll pair <ll, ll>
il char gc() { char cnt; while((cnt = getchar()) <= ' ') ; return cnt; }
il int rd() {
	char cnt; int x, f = 1;
	while(!isdigit(cnt = getchar())) if(cnt == '-') f *= -1;
	x = cnt ^ 48;
	while(isdigit(cnt = getchar())) x = (x << 3) + (x << 1) + (cnt ^ 48);
	return x * f;
}
void ACehomoxue();
signed main() {
	srand(time(0));
	// freopen(".in", "r", stdin);
	// freopen(".out", "w", stdout);
	int t = 1;
	// t = rd();
	while(t--) ACehomoxue();
	AK;
}
const int mod = 998244353, maxn = 5 * 1e5 + 18;

int n, m;

class xds {
    struct ele {
        int mx, cnt, add, addmx, ans, sum;
        void clr() { mx = ans = -1e18, cnt = add = addmx = sum = 0; }
        void clrtag() { add = addmx = 0; }
        void upd(const ele &a) {
            if(!a.cnt) AC;
            sum += a.sum, cnt += a.cnt;
            ans = max(ans, a.ans);
            mx = max(mx, a.mx);
        }
    } ;
    struct tree {
        int l, r;
        ele mx, se;
    } t[maxn << 2];
    void push_up(int i) {
        t[i].mx.clr(), t[i].se.clr();
        if(t[i * 2].mx.mx > t[i * 2 + 1].mx.mx) {
            t[i].mx.upd(t[i * 2].mx);
            t[i].se.upd(t[i * 2].se);
            t[i].se.upd(t[i * 2 + 1].mx);
            t[i].se.upd(t[i * 2 + 1].se);
        } else if(t[i * 2].mx.mx < t[i * 2 + 1].mx.mx) {
            t[i].mx.upd(t[i * 2 + 1].mx);
            t[i].se.upd(t[i * 2 + 1].se);
            t[i].se.upd(t[i * 2].mx);
            t[i].se.upd(t[i * 2].se);
        } else {
            t[i].mx.upd(t[i * 2].mx);
            t[i].mx.upd(t[i * 2 + 1].mx);
            t[i].se.upd(t[i * 2].se);
            t[i].se.upd(t[i * 2 + 1].se);
        }
    }
    void mdf(ele &s, int x, int mx) {
        if(!s.cnt) AC;
        s.addmx = max(s.addmx, s.add + mx);
        s.ans = max(s.ans, s.mx + mx);
        s.add += x, s.mx += x;
        s.sum += s.cnt * x;
    }
    #define lazytag(x) x.mx == val ? mdf(x, t[i].mx.add, t[i].mx.addmx) : mdf(x, t[i].se.add, t[i].se.addmx)
    void push_down(int i) { 
        int val = max(t[i * 2].mx.mx, t[i * 2 + 1].mx.mx);
        lazytag(t[i * 2].mx), lazytag(t[i * 2].se), lazytag(t[i * 2 + 1].mx), lazytag(t[i * 2 + 1].se);
        t[i].mx.clrtag(), t[i].se.clrtag(); 
    }
public:
    void build(int i, int l, int r, int *a) {
        t[i].l = l, t[i].r = r, t[i].mx.clr(), t[i].se.clr();
        if(l == r) {
            t[i].mx.sum = t[i].mx.ans = t[i].mx.mx = a[l];
            t[i].mx.cnt = 1;
            AC;
        }
        int mid = l + r >> 1;
        build(i * 2, l, mid, a);
        build(i * 2 + 1, mid + 1, r, a);
        push_up(i);
    }
    void add(int i, int l, int r, int x) {
        if(t[i].l >= l && t[i].r <= r) {
            mdf(t[i].mx, x, x);
            mdf(t[i].se, x, x);
            AC;
        }
        push_down(i);
        int mid = t[i].l + t[i].r >> 1;
        if(l <= mid) add(i * 2, l, r, x);
        if(r > mid) add(i * 2 + 1, l, r, x);
        push_up(i);
    }
    void updata(int i, int l, int r, int x) {
        if(t[i].l >= l && t[i].r <= r) {
            if(t[i].mx.mx <= x) AC;
            if(t[i].se.mx >= x) {
                push_down(i);
                updata(i * 2, l, r, x);
                updata(i * 2 + 1, l, r, x);
                push_up(i);
                AC;
            }
            x = x - t[i].mx.mx;
            mdf(t[i].mx, x, x);
            AC;
        }
        push_down(i);
        int mid = t[i].l + t[i].r >> 1;
        if(l <= mid) updata(i * 2, l, r, x);
        if(r > mid) updata(i * 2 + 1, l, r, x);
        push_up(i);
    }
    il int getsum(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].mx.sum + t[i].se.sum;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = 0;
        if(l <= mid) res += getsum(i * 2, l, r);
        if(r > mid) res += getsum(i * 2 + 1, l, r);
        return res;
    }
    il int getmax(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return t[i].mx.mx;
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = -1e18;
        if(l <= mid) res = max(res, getmax(i * 2, l, r));
        if(r > mid) res = max(res, getmax(i * 2 + 1, l, r));
        return res;
    }
    il int query(int i, int l, int r) {
        if(t[i].l >= l && t[i].r <= r) return max(t[i].mx.ans, t[i].se.ans);
        push_down(i);
        int mid = t[i].l + t[i].r >> 1, res = -1e18;
        if(l <= mid) res = max(res, query(i * 2, l, r));
        if(r > mid) res = max(res, query(i * 2 + 1, l, r));
        return res;
    }
} ds;

int a[maxn];

void ACehomoxue() {
	n = rd(), m = rd();
    for(int i = 1; i <= n; i++) a[i] = rd();
    ds.build(1, 1, n, a);
    for(int opt, l, r; m--; ) {
        opt = rd(), l = rd(), r = rd();
        if(opt == 1) ds.add(1, l, r, rd());
        if(opt == 2) ds.updata(1, l, r, rd());
        if(opt == 3) cout << ds.getsum(1, l, r), el;
        if(opt == 4) cout << ds.getmax(1, l, r), el;
        if(opt == 5) cout << ds.query(1, l, r), el;
    }
}
posted @ 2026-08-11 21:30  ACehomoxue  阅读(6)  评论(1)    收藏  举报