1703. 吉老师线段树

https://oi-wiki.org/ds/seg-beats/

维护操作:① 区间每个数与 t\min ② 输出区间和 ③ 输出区间最大值

对每个节点区间:维护该区间最大值 mx、最大值出现次数 se 、严格次大值 cnt

对操作 1

  • mx\le t ,整个区间都没 t 大,不操作 (相等也等于没操作)
  • se < t < mx ,那么所有最大值都变成 t ,次大值和更小的值都不变,所以 cntmx 被删掉,再加上 cntt ,即区间更新 cnt(t-mx) ,并记录懒标记
  • t\le se ,递归往下处理子区间

对操作 2,3 ,有手就行

处理 pushup

  • 若左右子区间最值一样, cnt 翻倍, se 取左右 se 较大者, mx 任取左右(都一样)
  • 否则, mx,cnt 取大者, se 让小区间 mx 和大区间 se 取最值

处理 pushdown

  • 懒标记是 t 的懒标记,根据题意可以取一些诸如无穷小代表无懒标记

处理建树:

  • 初始次大值建无穷小

参考代码:

#include <bits/stdc++.h> using namespace std; typedef long long ll; #define sc(x) scanf("%lld", &x) #define mn 400010 #define lfs p << 1 #define rfs p << 1 | 1 #define mkcf ll cf = (lf + rf) >> 1 #define neg -1 ll n, m, c, lc, rc, v, a[mn], s[mn], mx[mn], se[mn], cnt[mn], laz[mn], ans; void pushup(ll p) { s[p] = s[lfs] + s[rfs]; if (mx[lfs] == mx[rfs]) { mx[p] = mx[lfs]; cnt[p] = cnt[lfs] + cnt[rfs]; se[p] = max(se[lfs], se[rfs]); } else if (mx[lfs] > mx[rfs]) { mx[p] = mx[lfs]; cnt[p] = cnt[lfs]; se[p] = max(se[lfs], mx[rfs]); } else if (mx[lfs] < mx[rfs]) { mx[p] = mx[rfs]; cnt[p] = cnt[rfs]; se[p] = max(se[rfs], mx[lfs]); } } void build(ll p, ll lf, ll rf) { laz[p] = -1; if (lf == rf) { s[p] = mx[p] = a[lf]; cnt[p] = 1; se[p] = -1; return; } mkcf; build(lfs, lf, cf); build(rfs, cf + 1, rf); pushup(p); } void pushd(ll p, ll nw) { if (mx[p] <= nw) { return; } s[p] += cnt[p] * (nw - mx[p]); mx[p] = laz[p] = nw; } void pushdown(ll p) { if (laz[p] == -1) { return; } pushd(lfs, laz[p]); pushd(rfs, laz[p]); laz[p] = -1; } void update(ll p, ll lf, ll rf) { if (mx[p] <= v) { return; } if (lf >= lc && rf <= rc && se[p] < v) { return pushd(p, v); } pushdown(p); mkcf; if (cf >= lc) { update(lfs, lf, cf); } if (cf < rc) { update(rfs, cf + 1, rf); } pushup(p); } void query_mx(ll p, ll lf, ll rf) { if (lf >= lc && rf <= rc) { ans = max(ans, mx[p]); return; } pushdown(p); mkcf; if (cf >= lc) { query_mx(lfs, lf, cf); } if (cf < rc) { query_mx(rfs, cf + 1, rf); } } void query_sum(ll p, ll lf, ll rf) { if (lf >= lc && rf <= rc) { ans += s[p]; return; } pushdown(p); mkcf; if (cf >= lc) { query_sum(lfs, lf, cf); } if (cf < rc) { query_sum(rfs, cf + 1, rf); } } signed main() { sc(n), sc(m); for (ll i = 1; i <= n; ++i) { sc(a[i]); } build(1, 1, n); while (m--) { sc(c), sc(lc), sc(rc); if (c == 0) { sc(v); update(1, 1, n); } else if (c == 1) { ans = -1; query_mx(1, 1, n); printf("%lld\n", ans); } else { ans = 0; query_sum(1, 1, n); printf("%lld\n", ans); } } return 0; }