传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3083
【题解】
树链剖分,然后换根+询问子树这个是经典套路,分类讨论即可。
复杂度$O(nlog^2n)$
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 1e5 + 10, M = 2e5 + 10, SN = 262144 + 5; const int mod = 1e9+7, inf = 1e9; int n, m, d[N], rt; int head[N], nxt[M], to[M], tot = 0; inline void add(int u, int v) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; } inline void adde(int u, int v) { add(u, v), add(v, u); } int fa[N][18], dep[N], sz[N], son[N]; inline void dfs(int x, int par = 0) { fa[x][0] = par; dep[x] = dep[par] + 1; sz[x] = 1; son[x] = 0; for (int i=1; i<=17; ++i) fa[x][i] = fa[fa[x][i-1]][i-1]; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == par) continue; dfs(to[i], x); sz[x] += sz[to[i]]; if(!son[x] || sz[to[i]] > sz[son[x]]) son[x] = to[i]; } } int top[N], seq[N], dfn[N], DFN = 0; inline void dfs2(int x, int tp, int par = 0) { ++DFN; dfn[x] = DFN, seq[DFN] = d[x]; top[x] = tp; if(son[x]) dfs2(son[x], tp, x); for (int i=head[x]; i; i=nxt[i]) if(to[i] != par && to[i] != son[x]) dfs2(to[i], to[i], x); } inline int lca(int u, int v) { if(dep[u] < dep[v]) swap(u, v); for (int i=17; ~i; --i) if((dep[u] - dep[v]) & (1<<i)) u = fa[u][i]; if(u == v) return u; for (int i=17; ~i; --i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0]; } inline int jump(int x, int d) { for (int i=17; ~i; --i) if(d & (1<<i)) x = fa[x][i]; return x; } struct SMT { int w[SN]; int cov[SN]; bool hc[SN]; # define ls (x<<1) # define rs (x<<1|1) inline void up(int x) { w[x] = min(w[ls], w[rs]); } inline void pushcov(int x, int cv) { hc[x] = 1; cov[x] = cv; w[x] = cv; } inline void down(int x) { if(hc[x]) { pushcov(ls, cov[x]); pushcov(rs, cov[x]); cov[x] = hc[x] = 0; } } inline void build(int x, int l, int r) { cov[x] = hc[x] = 0; if(l == r) { w[x] = seq[l]; return ; } int mid = l+r>>1; build(ls, l, mid); build(rs, mid+1, r); up(x); } inline void cover(int x, int l, int r, int L, int R, int c) { if(L <= l && r <= R) { pushcov(x, c); return ; } down(x); int mid = l+r>>1; if(L <= mid) cover(ls, l, mid, L, R, c); if(R > mid) cover(rs, mid+1, r, L, R, c); up(x); } inline int gmin(int x, int l, int r, int L, int R) { if(L > R) return inf; if(L <= l && r <= R) return w[x]; down(x); int mid = l+r>>1; if(R <= mid) return gmin(ls, l, mid, L, R); else if(L > mid) return gmin(rs, mid+1, r, L, R); else return min(gmin(ls, l, mid, L, R), gmin(rs, mid+1, r, L, R)); } # undef ls # undef rs }T; inline void modify(int u, int v, int c) { while(top[u] != top[v]) { if(dep[top[u]] < dep[top[v]]) swap(u, v); T.cover(1, 1, n, dfn[top[u]], dfn[u], c); u = fa[top[u]][0]; } if(dfn[u] > dfn[v]) swap(u, v); T.cover(1, 1, n, dfn[u], dfn[v], c); } inline int query(int x) { if(rt == x) return T.gmin(1, 1, n, 1, n); int p = lca(x, rt); if(p != x) return T.gmin(1, 1, n, dfn[x], dfn[x] + sz[x] - 1); int D = dep[rt] - dep[x], y = jump(rt, D-1); return min(T.gmin(1, 1, n, 1, dfn[y] - 1), T.gmin(1, 1, n, dfn[y] + sz[y], n)); } int main() { cin >> n >> m; for (int i=1, u, v; i<n; ++i) { scanf("%d%d", &u, &v); adde(u, v); } for (int i=1; i<=n; ++i) scanf("%d", d+i); scanf("%d", &rt); dfs(rt); dfs2(rt, rt); T.build(1, 1, n); register int opt, a, b, c; while(m--) { scanf("%d", &opt); if(opt == 1) { scanf("%d", &a); rt = a; } else if(opt == 2) { scanf("%d%d%d", &a, &b, &c); modify(a, b, c); } else { scanf("%d", &a); printf("%d ", query(a)); } } return 0; }