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;
}
}

浙公网安备 33010602011771号