【题目链接】
【思路要点】
- 建出 支配树 ,剩余的操作均可以通过轻重链剖分+线段树解决。
- 时间复杂度 O ( Q L o g 2 N + M ) O(QLog^2N+M) O(QLog2N+M) 。
- 另外,等到笔者写完可持久化后才发现这个题的可持久化是假的,只需要将之前进行的操作减回去即可,这样做空间复杂度就不会高达 O ( N L o g 2 N ) O(NLog^2N) O(NLog2N) 了。
但可持久化的版本过了,就不重写了。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int MAXP = 3e6 + 5; const int MAXLOG = 17; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc, tag; long long sum; } a[MAXP]; int n, size, version, root[MAXN]; void build(int &root, int l, int r, int *val, int *p) { if (root == 0) root = ++size; if (l == r) { a[root].sum = val[p[l]]; return; } int mid = (l + r) / 2; build(a[root].lc, l, mid, val, p); build(a[root].rc, mid + 1, r, val, p); a[root].sum = a[a[root].lc].sum + a[a[root].rc].sum; } void init(int x, int *val, int *p) { n = x; size = 0; build(root[0], 1, n, val, p); } int modify(int root, int l, int r, int ql, int qr, int delta) { int ans = ++size; a[ans] = a[root]; a[ans].sum += (qr - ql + 1ll) * delta; if (l == ql && r == qr) { a[ans].tag += delta; return ans; } int mid = (l + r) / 2; if (mid >= ql) a[ans].lc = modify(a[root].lc, l, mid, ql, min(mid, qr), delta); if (mid + 1 <= qr) a[ans].rc = modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, delta); return ans; } void advance() { version++; root[version] = root[version - 1]; } void modify(int l, int r, int delta, bool stay) { version++; root[version] = modify(root[version - 1], 1, n, l, r, delta); if (stay) { root[version - 1] = root[version]; version--; } } long long query(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].sum; long long ans = (qr - ql + 1ll) * a[root].tag; int mid = (l + r) / 2; if (mid >= ql) ans += query(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) ans += query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); return ans; } long long query(int ql, int qr) { return query(root[version], 1, n, ql, qr); } void reverse(int cnt) { if (version >= cnt) version -= cnt; else version = 0; } } ST; int sdom[MAXN], idom[MAXN], val[MAXN]; int n, m, timer, dfn[MAXN], rit[MAXN], depth[MAXN]; int size[MAXN], son[MAXN], p[MAXN], up[MAXN]; int f[MAXN], father[MAXN][MAXLOG], home[MAXN]; vector <int> a[MAXN], b[MAXN], c[MAXN]; void mfs(int pos) { dfn[pos] = ++timer, p[timer] = pos; for (unsigned i = 0; i < a[pos].size(); i++) if (dfn[a[pos][i]] == 0) { father[a[pos][i]][0] = pos; mfs(a[pos][i]); } } void dfs(int pos, int fa) { size[pos] = 1, son[pos] = 0; depth[pos] = depth[fa] + 1; father[pos][0] = fa; for (int i = 1; i < MAXLOG; i++) father[pos][i] = father[father[pos][i - 1]][i - 1]; for (unsigned i = 0; i < a[pos].size(); i++) { dfs(a[pos][i], pos); size[pos] += size[a[pos][i]]; if (size[a[pos][i]] > size[son[pos]]) son[pos] = a[pos][i]; } } void efs(int pos, int from) { up[pos] = from; dfn[pos] = ++timer, p[timer] = pos; if (son[pos]) efs(son[pos], from); for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != son[pos]) efs(a[pos][i], a[pos][i]); rit[pos] = timer; } int F(int x) { if (x == f[x]) return x; int tmp = f[x]; f[x] = F(tmp); if (sdom[home[tmp]] < sdom[home[x]]) home[x] = home[tmp]; return f[x]; } int gethome(int pos) { F(pos); return home[pos]; } int lca(int x, int y) { if (depth[x] < depth[y]) swap(x, y); for (int i = MAXLOG - 1; i >= 0; i--) if (depth[father[x][i]] >= depth[y]) x = father[x][i]; if (x == y) return x; for (int i = MAXLOG - 1; i >= 0; i--) if (father[x][i] != father[y][i]) { x = father[x][i]; y = father[y][i]; } return father[x][0]; } bool cmp(int x, int y) { return dfn[x] < dfn[y]; } int main() { read(n), read(m); for (int i = 1; i <= n; i++) read(val[i]); for (int i = 1; i <= m; i++) { int x, y; read(x), read(y); a[x].push_back(y); b[y].push_back(x); } mfs(1); for (int i = 1; i <= timer; i++) { sdom[p[i]] = i; home[p[i]] = f[p[i]] = p[i]; } for (int i = timer; i >= 2; i--) { int pos = p[i]; for (unsigned i = 0; i < b[pos].size(); i++) if (dfn[b[pos][i]]) chkmin(sdom[pos], sdom[gethome(b[pos][i])]); c[sdom[pos]].push_back(pos); f[pos] = father[pos][0]; int tmp = dfn[father[pos][0]]; for (unsigned i = 0; i < c[tmp].size(); i++) { int tnp = gethome(c[tmp][i]); if (sdom[tnp] == tmp) idom[c[tmp][i]] = tmp; else idom[c[tmp][i]] = dfn[tnp]; } c[tmp].clear(); } for (int i = 1; i <= n; i++) a[i].clear(); for (int i = 2; i <= timer; i++) { int pos = p[i]; if (idom[pos] == sdom[pos]) idom[pos] = p[idom[pos]]; else idom[pos] = idom[p[idom[pos]]]; a[idom[pos]].push_back(pos); } timer = 0; memset(dfn, 0, sizeof(dfn)); dfs(1, 0); efs(1, 1); ST.init(n, val, p); int q; read(q); while (q--) { char opt = getchar(); while (opt != 'C' && opt != 'Q' && opt != 'R') opt = getchar(); if (opt == 'C') { int type, x, y; read(type), read(x), read(y); if (dfn[x] == 0) { ST.advance(); continue; } if (type == 1) ST.modify(dfn[x], dfn[x], y, false); if (type == 2) ST.modify(dfn[x], rit[x], y, false); if (type == 3) { bool tmp = false; while (x != 0) { ST.modify(dfn[up[x]], dfn[x], y, tmp); x = father[up[x]][0]; tmp = true; } } } if (opt == 'Q') { int type, x; read(type), read(x); if (type == 1) { if (dfn[x] == 0) writeln(0); else writeln(ST.query(dfn[x], rit[x])); } if (type == 2) { if (dfn[x] == 0) writeln(0); else { long long ans = 0; while (x != 0) { ans += ST.query(dfn[up[x]], dfn[x]); x = father[up[x]][0]; } writeln(ans); } } if (type == 3) { static int pos[MAXN]; for (int i = 1; i <= x; i++) read(pos[i]); sort(pos + 1, pos + x + 1, cmp); if (dfn[pos[1]] == 0) writeln(0); else { long long ans = 0; for (int i = 1; i <= x; i++) { int tmp = pos[i]; while (tmp != 0) { ans += ST.query(dfn[up[tmp]], dfn[tmp]); tmp = father[up[tmp]][0]; } tmp = lca(pos[i], pos[i - 1]); while (tmp != 0) { ans -= ST.query(dfn[up[tmp]], dfn[tmp]); tmp = father[up[tmp]][0]; } } writeln(ans); } } } if (opt == 'R') { int x; read(x); ST.reverse(x); } } return 0; }