HDU 5682 zxa and leaf
zxa and leaf
题意:
给树上所有点赋一个权值,一条边的权值是两个端点的权值差,使最大的边的权值最小。其中k个叶子节点已经赋值。
分析:
二分一个答案mid,然后dp一遍,求每个点的取值范围。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 100005; struct Edge{ int to, nxt; } e[N]; int head[N], fa[N], L[N], R[N], w[N], En, n; inline void add_edge(int u,int v) { ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En; ++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En; } void dfs(int u,int x) { for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa[u]) continue; fa[v] = u; dfs(v, x); L[u] = max(L[u], L[v] - x); R[u] = min(R[u], R[v] + x); } } bool check(int x) { for (int i = 1; i <= n; ++i) if (w[i]) L[i] = R[i] = w[i]; else L[i] = 0, R[i] = 1e9; dfs(1, x); for (int i = 1; i <= n; ++i) if (L[i] > R[i]) return 0; return 1; } void solve() { n = read();int k = read(); for (int i = 1; i < n; ++i) { int u = read(), v = read(); add_edge(u, v); } for (int i = 1; i <= k; ++i) w[read()] = read(); int l = 0, r = 1e9, ans; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } printf("%d\n", ans); En = 0; for (int i = 1; i <= n; ++i) head[i] = w[i] = fa[i] = 0; } int main() { for (int T = read(); T --; solve()) ; return 0; }