[洛谷P3979]遥远的国度
题目大意:有一棵$n$个点的树,每个点有一个点权,有三种操作:
- $1\;x:$把根变成$x$
- $2\;u\;v\;x:$把路径$u->v$上的点权改为$x$
- $3\;x:$询问以$x$为根的子树中最小的点权
题解:树剖,发现换根操作比较困难,可以进行一波分类讨论(下面的$lca$以及子树都是在以$1$为根的情况下(其实任意一个固定的点均可)
- $root=x:$就是询问整棵树
- $lca(root,x)\not=x:$就是正常询问$x$的子树
- $lca(root,x)=x:$就是整棵树减去$root$所在的子树
然后步骤三的减去$root$所在的子树中的找这棵子树可以用倍增来求
卡点:步骤三中只查询了$x$的子树减去$root$子树
C++ Code:
#include <algorithm> #include <cstdio> #include <cctype> namespace std { struct istream { #define M (1 << 24 | 3) char buf[M], *ch = buf - 1; inline istream() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif fread(buf, 1, M, stdin); } inline istream& operator >> (int &x) { while (isspace(*++ch)); for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15); return *this; } #undef M } cin; struct ostream { #define M (1 << 24 | 3) char buf[M], *ch = buf - 1; inline ostream& operator << (int x) { if (!x) { *++ch = '0'; return *this; } static int S[20], *top; top = S; while (x) { *++top = x % 10 ^ 48; x /= 10; } for (; top != S; --top) *++ch = *top; return *this; } inline ostream& operator << (const char x) {*++ch = x; return *this;} inline ~ostream() { #ifndef ONLINE_JUDGE freopen("output.txt", "w", stdout); #endif fwrite(buf, 1, ch - buf + 1, stdout); } #undef M } cout; } #define maxn 100010 const int inf = 0x7fffffff; int head[maxn], cnt; struct Edge { int to, nxt; } e[maxn << 1]; inline void addedge(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } int n, m; int w[maxn], W[maxn]; namespace SgT { int V[maxn << 2], tg[maxn << 2]; inline void pushdown(int rt) { int &__tg = tg[rt]; V[rt << 1] = tg[rt << 1] = V[rt << 1 | 1] = tg[rt << 1 | 1] = __tg; __tg = 0; } int L, R, num; void build(int rt, int l, int r) { if (l == r) { V[rt] = W[l]; return ; } int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); V[rt] = std::min(V[rt << 1], V[rt << 1 | 1]); } void __modify(int rt, int l, int r) { if (L <= l && R >= r) { V[rt] = tg[rt] = num; return ; } int mid = l + r >> 1; if (tg[rt]) pushdown(rt); if (L <= mid) __modify(rt << 1, l, mid); if (R > mid) __modify(rt << 1 | 1, mid + 1, r); V[rt] = std::min(V[rt << 1], V[rt << 1 | 1]); } void modify(int __L, int __R, int __num) { L = __L, R = __R, num = __num; __modify(1, 1, n); } int ans; void __query(int rt, int l, int r) { if (L <= l && R >= r) { ans = std::min(ans, V[rt]); return ; } int mid = l + r >> 1; if (tg[rt]) pushdown(rt); if (L <= mid) __query(rt << 1, l, mid); if (R > mid) __query(rt << 1 | 1, mid + 1, r); } int query(int __L, int __R) { L = __L, R = __R; ans = inf; __query(1, 1, n); return ans; } } int root; int fa[maxn], sz[maxn], dfn[maxn], idx; int son[maxn], top[maxn], dep[maxn]; namespace BZ { #define M 17 int fa[maxn][M + 1]; inline void init(int u) { *fa[u] = ::fa[u]; for (int i = 1; i <= M; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; } inline int get_son(int x, int y) { for (int i = M; ~i; i--) if (dep[fa[x][i]] > dep[y]) x = fa[x][i]; return x; } #undef M } using BZ::get_son; void dfs1(int u) { BZ::init(u); sz[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[u]) { fa[v] = u; dep[v] = dep[u] + 1; dfs1(v); sz[u] += sz[v]; if (!son[u] || sz[v] > sz[son[u]]) son[u] = v; } } } void dfs2(int u) { dfn[u] = ++idx; int v = son[u]; if (v) top[v] = top[u], dfs2(v); for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[u] && v != son[u]) { top[v] = v; dfs2(v); } } } inline int LCA(int x, int y) { if (x == y) return x; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) std::swap(x, y); x = fa[top[x]]; } return dep[x] > dep[y] ? y : x; } void modify(int x, int y, int z) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) std::swap(x, y); SgT::modify(dfn[top[x]], dfn[x], z); x = fa[top[x]]; } if (dep[x] > dep[y]) std::swap(x, y); SgT::modify(dfn[x], dfn[y], z); } inline int query(int x) { if (root == x) return SgT::query(1, n); if (LCA(x, root) != x) return SgT::query(dfn[x], dfn[x] + sz[x] - 1); const int S = get_son(root, x), l = dfn[S], r = dfn[S] + sz[S] - 1; int ans = inf; if (1 < l) ans = SgT::query(1, l - 1); if (r < n) ans = std::min(ans, SgT::query(r + 1, n)); return ans; } int main() { std::cin >> n >> m; for (int i = 1, a, b; i < n; i++) { std::cin >> a >> b; addedge(a, b); } dfs1(1); dfs2(top[1] = 1); for (int i = 1; i <= n; i++) std::cin >> w[i]; for (int i = 1; i <= n; i++) W[dfn[i]] = w[i]; SgT::build(1, 1, n); std::cin >> root; while (m --> 0) { int op, u, v, x; std::cin >> op >> u; switch (op) { case 1: root = u; break; case 2: std::cin >> v >> x; modify(u, v, x); break; case 3: std::cout << query(u) << '\n'; } } return 0; }