題目大意:有一棵$n$個點的帶邊權樹,第$i$個點有兩個值$w_i,d_i$,表示在這個點作標記的代價爲$w_i$,且這個點距離$d_i$之內至少要有一個點被標記,爲最小代價。$n\leqslant6000$ios
題解:記$f[i][j]$表示以$i$爲根的子樹所有知足條件,且第$i$個點是因爲$j$被標記致使的,$g[i]$表示以$i$爲根的子樹所有知足條件的代價。$f[i][j]=w_i+\min\limits_{v\in son[u]}\{f[v][j]-w_i,g[v]\}$spa
卡點:無blog
C++ Code:ci
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> const int maxn = 6e3 + 10, inf = 0x3f3f3f3f; int n, w[maxn], d[maxn]; int head[maxn], cnt; struct Edge { int to, nxt, w; } e[maxn << 1]; void addedge(int a, int b, int c) { e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt; e[++cnt] = (Edge) { a, head[b], c }; head[b] = cnt; } int dis[maxn][maxn], f[maxn][maxn], g[maxn]; void dfs0(int *dis, int u, int fa = 0) { for (int i = head[u], v; i; i = e[i].nxt) { v = e[i].to; if (v != fa) { dis[v] = dis[u] + e[i].w; dfs0(dis, v, u); } } } void dfs(int u, int fa = 0) { for (int i = head[u]; i; i = e[i].nxt) if (e[i].to != fa) dfs(e[i].to, u); for (int i = 1; i <= n; ++i) if (dis[u][i] <= d[u]) { f[u][i] = w[i]; for (int j = head[u], v; j; j = e[j].nxt) { v = e[j].to; if (v != fa) f[u][i] += std::min(f[v][i] - w[i], g[v]); } g[u] = std::min(g[u], f[u][i]); } } int main() { std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); std::cin >> n; for (int i = 1; i <= n; ++i) std::cin >> w[i]; for (int i = 1; i <= n; ++i) std::cin >> d[i]; for (int i = 1, a, b, c; i < n; ++i) { std::cin >> a >> b >> c; addedge(a, b, c); } for (int i = 1; i <= n; ++i) dfs0(dis[i], i); memset(f, 0x3f, sizeof f), memset(g, 0x3f, sizeof g); dfs(1); std::cout << g[1] << '\n'; return 0; }