题目链接 Jamie and Tree
题意 给定一棵树,现在有下列操作:
$1$、把当前的根换成$v$;$2$、找到最小的同时包含$u$和$v$的子树,然后把这棵子树里面的所有点的值加$x$;
$3$、查询以$v$为根的子树的点权之和。
这道题其他都是常规操作,就是当前根结点为$cnt$的时候求$x$和$y$的$LCA$(操作$2$要用到)
我们假定解题的时候根一直不变(我一般都设$1$为根结点)
答案为$LCA(x,y)$ $xor$ $LCA(x, cnt)$ $xor$ $LCA(y, cnt)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 1e5 + 10; const int ass = 4e5; vector <int> v[N]; int ti; int tot; int n, m; int fp[N]; int deep[N], f[N], st[N], ed[N], father[N], sz[N], son[N]; int top[N]; int cnt; LL a[N]; LL sum[N << 2], lazy[N << 2]; void dfs1(int x, int fa, int dep){ deep[x] = dep; father[x] = fa; son[x] = 0; sz[x] = 1; st[x] = ++ti; for (auto u : v[x]){ if (u == fa) continue; dfs1(u, x, dep + 1); sz[x] += sz[u]; if (sz[son[x]] < sz[u]) son[x] = u; } ed[x] = ti; } void dfs2(int x, int tp){ top[x] = tp; f[x] = ++tot; fp[f[x]] = x; if (son[x]) dfs2(son[x], tp); for (auto u : v[x]){ if (u == father[x] || u == son[x]) continue; dfs2(u, u); } } int LCA(int x, int y){ for (; top[x] ^ top[y]; ){ if (deep[top[x]] < deep[top[y]]) swap(x, y); x = father[top[x]]; } return deep[x] > deep[y] ? y : x; } int twz(int x, int y){ int t; for (; top[x] ^ top[y]; ) t = top[y], y = father[top[y]]; return x == y ? t : son[x]; } inline void pushup(int i){ sum[i] = sum[i << 1] + sum[i << 1 | 1]; } inline void pushdown(int i, int L, int R){ if (L == R) return; int mid = (L + R) >> 1; lazy[i << 1] += 1ll * lazy[i]; sum[i << 1] += 1ll * lazy[i] * (mid - L + 1); lazy[i << 1 | 1] += 1ll * lazy[i]; sum[i << 1 | 1] += 1ll * lazy[i] * (R - mid); lazy[i] = 0; } void build(int i, int L, int R){ if (L == R){ sum[i] = 1ll * a[fp[L]]; return; } int mid = (L + R) >> 1; build(lson); build(rson); pushup(i); } void update(int i, int L, int R, int l, int r, LL val){ if (l == L && R == r){ sum[i] += 1ll * val * (R - L + 1); lazy[i] += 1ll * val; return ; } pushdown(i, L, R); int mid = (L + R) >> 1; if (r <= mid) update(lson, l, r, val); else if (l > mid) update(rson, l, r, val); else{ update(lson, l, mid, val); update(rson, mid + 1, r, val); } pushup(i); } LL query(int i, int L, int R, int l, int r){ pushdown(i, L, R); if (L == l && R == r) return sum[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return query(lson, l, mid) + query(rson, mid + 1, r); } LL calc(int x){ return query(1, 1, n, f[x], f[x] + sz[x] - 1); } LL work(int x, LL val){ update(1, 1, n, f[x], f[x] + sz[x] - 1, val); } int calc_lca(int x, int y, int cnt){ return LCA(x, y) ^ LCA(x, cnt) ^ LCA(y, cnt); } int main(){ scanf("%d%d", &n, &m); rep(i, 1, n) scanf("%lld", a + i); ti = 0; rep(i, 2, n){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } dfs1(1, 0, 0); dfs2(1, 1); build(1, 1, n); cnt = 1; int ca = 0; while (m--){ int op; scanf("%d", &op); if (op == 3){ int x; scanf("%d", &x); if (x == cnt){ printf("%lld ", calc(1)); continue; } int lca = LCA(x, cnt); if (lca == x){ int y = twz(x, cnt); printf("%lld ", calc(1) - calc(y)); continue; } printf("%lld ", calc(x)); } else if (op == 1){ int x; scanf("%d", &x); cnt = x; } else{ int x, y; LL val; scanf("%d%d%lld", &x, &y, &val); int z = calc_lca(x, y, cnt); if (z == cnt){ work(1, val); continue; } int lca = LCA(z, cnt); if (lca == z){ int yy = twz(z, cnt); work(1, val); work(yy, -val); continue; } work(z, val); } } return 0; }