Segment Tree Beats!(吉司機線段樹)
阿新 • • 發佈:2020-10-27
Segment Tree Beats
\(Q1.\)給定長度為\(n\)的序列\(A\),支援以下操作:1、區間取\(\min\);2、區間查詢最大值;3、區間求和。
const int N = 1000005; const int inf = 1<<30; int n, m, a[N]; #define lc (o << 1) #define rc (o << 1 | 1) int ma[N*4], se[N*4], tot[N*4]; ll sum[N*4]; void pushup(int o) { sum[o] = sum[lc] + sum[rc]; ma[o] = std::max(ma[lc], ma[rc]); se[o] = std::max(se[lc], se[rc]); if (ma[lc] != ma[rc]) chkmax(se[o], std::min(ma[lc], ma[rc])); tot[o] = (ma[o] == ma[lc] ? tot[lc] : 0) + (ma[o] == ma[rc] ? tot[rc] : 0); } void pushdown(int o) { if (ma[lc] > ma[o]) sum[lc] -= 1ll*(ma[lc]-ma[o])*tot[lc], ma[lc] = ma[o]; if (ma[rc] > ma[o]) sum[rc] -= 1ll*(ma[rc]-ma[o])*tot[rc], ma[rc] = ma[o]; } void build(int o, int l, int r) { if (l == r) { sum[o] = ma[o] = a[l], se[o] = -inf, tot[o] = 1; return; } int mid = l+r>>1; build(lc, l, mid), build(rc, mid+1, r); pushup(o); } void modify(int o, int l, int r, int x, int y, int v) { if (r < x || y < l) return; if (x <= l && r <= y && v > se[o]) { if (v >= ma[o]) return; sum[o] -= 1ll*(ma[o]-v)*tot[o]; ma[o] = v; return; } int mid = l+r>>1; pushdown(o); modify(lc, l, mid, x, y, v), modify(rc, mid+1, r, x, y, v); pushup(o); } int qmax(int o, int l, int r, int x, int y) { if (r < x || y < l) return -inf; if (x <= l && r <= y) return ma[o]; int mid = l+r>>1; pushdown(o); return std::max(qmax(lc, l, mid, x, y), qmax(rc, mid+1, r, x, y)); } ll qsum(int o, int l, int r, int x, int y) { if (r < x || y < l) return 0; if (x <= l && r <= y) return sum[o]; int mid = l+r>>1; pushdown(o); return qsum(lc, l, mid, x, y) + qsum(rc, mid+1, r, x, y); } int main() { for (int T = read(); T; T--) { n = read(), m = read(); rep(i, 1, n) a[i] = read(); build(1, 1, n); while (m--) { int ty = read(), x = read(), y = read(); if (!ty) { int t = read(); modify(1, 1, n, x, y, t); } else printf("%lld\n", ty == 1 ? qmax(1, 1, n, x, y) : qsum(1, 1, n, x, y)); } } return 0; }