UOJ169. 【UR #11】元旦老人與數列
阿新 • • 發佈:2019-01-10
傳送門
考慮用 \(segment~tree~beats\) 那一套理論,維護區間最小值 \(mn\) 和嚴格次小值 \(se\)
那麼可以直接 \(mlog^2n\) 維護前三個操作
考慮維護歷史最小值,先維護歷史最小標記
寫了寫發現 \(max\) 那個修改不好操作
對於 \(max\) 操作來說,只會在 \(mn< v <se\) 的時候打上標記
這就相當於區間內等於 \(mn\) 的權值都要變成 \(v\)
那麼 \(max\) 操作就可以變成對區間最小值的加法操作
而 \(v<se\),這樣就可以非常方便維護歷史最小值了
具體來說,維護下面幾個標記
- 區間最小值的加法標記
- 區間其它值的加法標記
- 區間最小值的歷史最小的加法標記
- 區間其它值的歷史最小的加法標記
下放的時候判斷一下是否是區間最小值就好了
# include <bits/stdc++.h> using namespace std; typedef long long ll; namespace IO { const int maxn(1 << 21 | 1); char obuf[maxn], ibuf[maxn], *iS, *iT, c, *oS = obuf, *oT = obuf + maxn - 1, st[60]; int f, tp; inline char Getc() { return iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++)) : *iS++; } template <class Int> inline void In(Int &x) { for (c = Getc(), f = 1; c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1; for (x = 0; c >= '0' && c <= '9'; c = Getc()) x = (x << 1) + (x << 3) + (c ^ 48); x *= f; } inline void Flush() { fwrite(obuf, 1, oS - obuf, stdout); oS = obuf; } inline void Putc(char c) { *oS++ = c; if (oS == oT) Flush(); } template <class Int> inline void Out(Int x) { if (x < 0) Putc('-'), x = -x; if (!x) Putc('0'); while (x) st[++tp] = x % 10 + '0', x /= 10; while (tp) Putc(st[tp--]); } } using IO :: In; using IO :: Out; using IO :: Putc; using IO :: Flush; const int maxn(2e6 + 5); const int inf(2e9); struct Min { int mn1, mn2; inline Min operator +(Min b) const { Min c; c.mn1 = min(mn1, b.mn1), c.mn2 = min(mn2, b.mn2); if (b.mn1 ^ c.mn1) c.mn2 = min(c.mn2, b.mn1); if (mn1 ^ c.mn1) c.mn2 = min(c.mn2, mn1); return c; } }; Min mn[maxn]; int n, m, hmn[maxn], addmn1[maxn], addmn2[maxn], addhmn1[maxn], addhmn2[maxn]; inline void Update(int x) { mn[x] = mn[x << 1] + mn[x << 1 | 1], hmn[x] = min(hmn[x << 1], hmn[x << 1 | 1]); } void Build(int x, int l, int r) { int mid; if (l == r) { In(mn[x].mn1), mn[x].mn2 = inf, hmn[x] = mn[x].mn1; return; } mid = (l + r) >> 1; Build(x << 1, l, mid), Build(x << 1 | 1, mid + 1, r); Update(x); } inline void Puttag(int x, int vmn1, int vmn2, int vhmn1, int vhmn2) { hmn[x] = min(hmn[x], mn[x].mn1 + vhmn1); addhmn1[x] = min(addhmn1[x], addmn1[x] + vhmn1); addhmn2[x] = min(addhmn2[x], addmn2[x] + vhmn2); addmn1[x] += vmn1, addmn2[x] += vmn2, mn[x].mn1 += vmn1; if (mn[x].mn2 ^ inf) mn[x].mn2 += vmn2; } inline void Pushdown(int x) { if (!addmn1[x] && !addmn2[x] && !addhmn1[x] && !addhmn2[x]) return; int ls, rs, now; ls = x << 1, rs = x << 1 | 1, now = min(mn[ls].mn1, mn[rs].mn1); if (now == mn[ls].mn1) Puttag(ls, addmn1[x], addmn2[x], addhmn1[x], addhmn2[x]); else Puttag(ls, addmn2[x], addmn2[x], addhmn2[x], addhmn2[x]); if (now == mn[rs].mn1) Puttag(rs, addmn1[x], addmn2[x], addhmn1[x], addhmn2[x]); else Puttag(rs, addmn2[x], addmn2[x], addhmn2[x], addhmn2[x]); addmn1[x] = addmn2[x] = addhmn1[x] = addhmn2[x] = 0; } void Modify_add(int x, int l, int r, int ql, int qr, int v) { int mid; if (ql <= l && qr >= r) { Puttag(x, v, v, v, v); return; } mid = (l + r) >> 1, Pushdown(x); if (ql <= mid) Modify_add(x << 1, l, mid, ql, qr, v); if (qr > mid) Modify_add(x << 1 | 1, mid + 1, r, ql, qr, v); Update(x); } void Modify_max(int x, int l, int r, int ql, int qr, int v) { int mid; if (mn[x].mn1 >= v) return; if (ql <= l && qr >= r && mn[x].mn2 > v) { Puttag(x, v - mn[x].mn1, 0, v - mn[x].mn1, 0); return; } mid = (l + r) >> 1, Pushdown(x); if (ql <= mid) Modify_max(x << 1, l, mid, ql, qr, v); if (qr > mid) Modify_max(x << 1 | 1, mid + 1, r, ql, qr, v); Update(x); } int Query_min(int x, int l, int r, int ql, int qr) { int mid, ret; if (ql <= l && qr >= r) return mn[x].mn1; mid = (l + r) >> 1, Pushdown(x), ret = inf; if (ql <= mid) ret = Query_min(x << 1, l, mid, ql, qr); if (qr > mid) ret = min(ret, Query_min(x << 1 | 1, mid + 1, r, ql, qr)); Update(x); return ret; } int Query_hmin(int x, int l, int r, int ql, int qr) { int mid, ret; if (ql <= l && qr >= r) return hmn[x]; mid = (l + r) >> 1, Pushdown(x), ret = inf; if (ql <= mid) ret = Query_hmin(x << 1, l, mid, ql, qr); if (qr > mid) ret = min(ret, Query_hmin(x << 1 | 1, mid + 1, r, ql, qr)); Update(x); return ret; } int main() { int i, op, l, r, v; In(n), In(m), Build(1, 1, n); while (m) { --m, In(op), In(l), In(r); if (op == 1) In(v), Modify_add(1, 1, n, l, r, v); else if (op == 2) In(v), Modify_max(1, 1, n, l, r, v); else if (op == 3) Out(Query_min(1, 1, n, l, r)), Putc('\n'); else Out(Query_hmin(1, 1, n, l, r)), Putc('\n'); } return Flush(), 0; }