题目链接 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\n", calc(1));
continue;
}
int lca = LCA(x, cnt);
if (lca == x){
int y = twz(x, cnt);
printf("%lld\n", calc(1) - calc(y));
continue;
}
printf("%lld\n", 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;
}