https://www.luogu.org/problemnew/show/P3979
3种情况
x=root,很显然此时应当查询整棵树
lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关
lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 using namespace std; typedef long long ll; typedef double dd; const int maxn=200010; const ll INF = (ll)1E14 + 9; int h[maxn], n, m, top[maxn], lca[maxn][21], son[maxn], edge, sz[maxn], dep[maxn]; int L[maxn], R[maxn], root, num, x, y, tx, ty, t, opt; ll val, a[maxn]; struct Edge { int to, ne; } e[maxn * 2]; struct Seg { ll minn, same; } seg[maxn << 2]; void close() { exit(0); } void addedge(int x,int y) { e[edge].to = y; e[edge].ne = h[x]; h[x] = edge++; } void dfs(int k,int from) { sz[k] = 1; dep[k] = dep[from] + 1; son[k] = 0; for (int p=h[k]; p!=-1; p=e[p].ne) { int to = e[p].to; if (to == from) continue; lca[to][0] = k; for (int i=1; i<=20; i++) lca[to][i] = lca[lca[to][i-1]][i-1]; dfs(to, k); sz[k] += sz[to]; if (sz[to] > sz[son[k]]) son[k] = to; } } void build(int k,int from) { L[k] = ++num; top[k] = from; if (son[k]) build(son[k], from); for (int p=h[k]; p!=-1; p=e[p].ne) { int to = e[p].to; if (to != lca[k][0] && to != son[k]) build(to, to); } R[k] = num; } int get_lca(int x,int y) { if (dep[x] < dep[y]) swap(x, y); int depth = dep[x] - dep[y]; for (int i=20; i>=0; i--) if (depth & (1 << i)) x = lca[x][i]; if (x == y) return x; for (int i=20; i>=0; i--) { if (lca[x][i] != lca[y][i]) { x = lca[x][i]; y = lca[y][i]; } } return lca[x][0]; } void pushup(int rt) { seg[rt].minn = min(seg[rt<<1].minn, seg[rt<<1|1].minn); } void same(int rt,ll val) { seg[rt].minn = val; seg[rt].same = val; } void pushdown(int rt) { if (seg[rt].same) { same(rt << 1, seg[rt].same); same(rt << 1 | 1, seg[rt].same); seg[rt].same = 0; } } void change(int L,int R,ll val,int l,int r,int rt) { if (L <= l && r <= R) { same(rt, val); return; } int mid = (l + r) >> 1; pushdown(rt); if (L <= mid) change(L,R,val,lson); if (mid + 1 <= R) change(L,R,val,rson); pushup(rt); } ll query(int L,int R,int l,int r,int rt) { if (L > R) return INF; if (L <= l && r <= R) { return seg[rt].minn; } int mid = (l + r) >> 1; pushdown(rt); ll ans = INF; if (L <= mid) ans = min(ans, query(L,R,lson)); if (mid + 1 <= R) ans = min(ans, query(L,R,rson)); pushup(rt); return ans; } void cc() { tx = top[x]; ty = top[y]; while (tx != ty) { if (dep[tx] < dep[ty]) { swap(x, y); swap(tx, ty); } change(L[tx], L[x], val, 1, n, 1); x = lca[tx][0]; tx = top[x]; } if (dep[x] < dep[y]) swap(x, y); change(L[y], L[x], val, 1, n, 1); } void work() { if (root == x) { printf("%lld ", seg[1].minn); return; } t = get_lca(root, x); if (t != x) { printf("%lld ", query(L[x], R[x], 1, n, 1)); return; } int depth = dep[root] - dep[x] - 1; int haha = root; for (int i=20; i>=0; i--) if (depth & (1 << i)) haha = lca[haha][i]; printf("%lld ", min(query(1, L[haha] - 1, 1, n, 1), query(R[haha] + 1, n, 1, n, 1)) ); } void init() { scanf("%d %d",&n,&m); memset(h, -1, sizeof(h)); for (int i=1; i<=n-1; i++) { scanf("%d %d",&x, &y); addedge(x, y); addedge(y, x); } for (int i=1; i<=n; i++) scanf("%lld",&a[i]); dfs(1, 0); build(1, 1); for (int i=1; i<=n; i++) change(L[i], L[i], a[i], 1, n, 1); scanf("%d",&root); while (m--) { scanf("%d",&opt); if (opt == 1) scanf("%d",&root); if (opt == 2) { scanf("%d %d %lld",&x,&y,&val); cc(); } if (opt == 3) { scanf("%d",&x); work(); } } } int main () { init(); close(); return 0; }