AcWing 955. 維護數列(splay插入,刪除,區間修改,區間翻轉,區間求和,區間求最大子段和)
阿新 • • 發佈:2021-08-03
解題思路
板子題,考察對\(splay\)的插入,刪除,區間修改,區間翻轉,區間求和,區間求最大子段和的基礎操作。
const int maxn = 1e6+10; int n, m, a[maxn]; struct Node { int s[2], v, p, sz; int sum, sm, lm, rm; int rev, same; void init(int _v, int _p) { sum = sm = v = _v, p = _p; lm = rm = max(_v, 0); s[0] = s[1] = rev = same = 0; //因為要回收再利用,所以都要初始化為0 sz = 1; } } tr[maxn]; int rt, q[maxn], tt; inline void push_up(int u) { Node &now = tr[u]; Node ls = tr[now.s[0]]; Node rs = tr[now.s[1]]; now.sz = ls.sz+rs.sz+1; now.sum = ls.sum+rs.sum+now.v; now.lm = max(ls.lm, ls.sum+rs.lm+now.v); now.rm = max(rs.rm, rs.sum+ls.rm+now.v); now.sm = max({ls.sm, rs.sm, ls.rm+now.v+rs.lm}); } inline void push_down(int u) { Node &now = tr[u]; Node &ls = tr[now.s[0]]; Node &rs = tr[now.s[1]]; if (now.same) { now.same = now.rev = 0; //如果u是葉子就不能更新了,也就是看u有沒有兒子 if (now.s[0]) { ls.same = 1; ls.v = now.v; ls.sum = ls.sz*now.v; if (now.v>0) ls.sm = ls.lm = ls.rm = ls.sum; //最大子段和至少要有一個數,所以ls.sm至少為now.v else ls.sm = now.v, ls.lm = ls.rm = 0; } if (now.s[1]) { rs.same = 1; rs.v = now.v; rs.sum = rs.sz*now.v; if (now.v>0) rs.sm = rs.lm = rs.rm = rs.sum; else rs.sm = now.v, rs.lm = rs.rm = 0; } } else if (now.rev) { ls.rev ^= 1; rs.rev ^= 1; swap(ls.s[0], ls.s[1]); swap(rs.s[0], rs.s[1]); swap(ls.lm, ls.rm); swap(rs.lm, rs.rm); now.rev = 0; } } int build(int l, int r, int p) { int mid = (l+r)>>1; int u = q[tt--]; tr[u].init(a[mid], p); if (l<mid) tr[u].s[0] = build(l, mid-1, u); if (r>mid) tr[u].s[1] = build(mid+1, r, u); push_up(u); return u; } void rotate(int x) { int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1]==x; tr[z].s[tr[z].s[1]==y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; push_up(y), push_up(x); } void splay(int x, int k) { while(tr[x].p!=k) { int y = tr[x].p, z = tr[y].p; if (z!=k) if ((tr[y].s[1]==x)^(tr[z].s[1]==y)) rotate(x); else rotate(y); rotate(x); } if (!k) rt = x; } int get_k(int k) { int u = rt; while(u) { push_down(u); int sz = tr[tr[u].s[0]].sz; if (sz>=k) u = tr[u].s[0]; else if (sz+1==k) return u; else k -= sz+1, u = tr[u].s[1]; } return 0; } void rec(int u) { if (!u) return; if (tr[u].s[0]) rec(tr[u].s[0]); if (tr[u].s[1]) rec(tr[u].s[1]); q[++tt] = u; } int main() { IOS; for (int i = 1; i<maxn; ++i) q[++tt] = i; cin >> n >> m; for (int i = 1; i<=n; ++i) cin >> a[i]; a[0] = a[n+1] = tr[0].sm = -INF; rt = q[tt]; build(0, n+1, 0); while(m--) { char op[20]; int pos, tot; cin >> op; if (!strcmp(op, "INSERT")) { cin >> pos >> tot; int L = get_k(pos+1), R = get_k(pos+2); splay(L, 0), splay(R, L); for (int i = 0; i<tot; ++i) cin >> a[i]; tr[R].s[0] = build(0, tot-1, R); push_up(R), push_up(L); } else if (!strcmp(op, "DELETE")) { cin >> pos >> tot; int L = get_k(pos), R = get_k(pos+tot+1); splay(L, 0), splay(R, L); rec(tr[R].s[0]); tr[R].s[0] = 0; push_up(R), push_up(L); } else if (!strcmp(op, "MAKE-SAME")) { int c; cin >> pos >> tot >> c; int L = get_k(pos), R = get_k(pos+tot+1); splay(L, 0), splay(R, L); Node &now = tr[tr[R].s[0]]; now.same = 1; now.v = c; now.sum = now.sz*c; if (c>0) now.sm = now.lm = now.rm = now.sum; else now.sm = c, now.lm = now.rm = 0; push_up(R), push_up(L); } else if (!strcmp(op, "REVERSE")) { cin >> pos >> tot; int L = get_k(pos), R = get_k(pos+tot+1); splay(L, 0), splay(R, L); Node &now = tr[tr[R].s[0]]; now.rev ^= 1; swap(now.s[0], now.s[1]); swap(now.lm, now.rm); push_up(R), push_up(L); } else if (!strcmp(op, "GET-SUM")) { cin >> pos >> tot; int L = get_k(pos), R = get_k(pos+tot+1); splay(L, 0), splay(R, L); cout << tr[tr[R].s[0]].sum << endl; } else if (!strcmp(op, "MAX-SUM")) { cout << tr[rt].sm << endl; } } return 0; }