题目链接:这里
题意:
zxa有一棵含有n个节点的无根树,包含(n−1)条无向边,点从1到n编号,定义每个点的度数为与这个点相连的边的数量,度数为1
的节点被称作这棵树的叶子节点。
zxa想给每个节点设置它的好看度,好看度必须为正整数。他的无根树有m(1≤m≤n)
个叶子节点,其中的k(1≤k≤m)
个叶子节点的好看度已经确定,zxa只需要设置其他节点的好看度。
zxa很好奇,如果令每条边的难看度是这条边所连接的两个节点的好看度差值的绝对值,整棵树的难看度是所有边的难看度中的最大值,那么这棵树的难看度最小是多少,你能帮助他吗?
解法:
//HDU 5682
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4+7;
int w[maxn], l[maxn], r[maxn], vis[maxn];
int n, k;
vector <int> E[maxn];
int dfs1(int x, int d){
for(int i = 0; i < E[x].size(); i++){
if(!vis[E[x][i]]){
vis[E[x][i]] = 1;
l[x] = max(l[x], dfs1(E[x][i], d));
}
}
return l[x] - d;
}
int dfs2(int x, int d){
for(int i = 0; i < E[x].size(); i++){
if(!vis[E[x][i]]){
vis[E[x][i]] = 1;
r[x] = min(r[x], dfs2(E[x][i], d));
}
}
return r[x] + d;
}
bool check(int mid){
for(int i = 1; i <= n; i++){
if(w[i]) l[i] = r[i] = w[i];
else l[i] = 0, r[i] = 1e9+7;
}
memset(vis, 0, sizeof(vis));
dfs1(1, mid);
memset(vis, 0, sizeof(vis));
dfs2(1, mid);
for(int i = 1; i <= n; i++){
if(r[i] < l[i]) return false;
}
return true;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
for(int i = 0; i < maxn; i++) E[i].clear();
for(int i = 0; i < maxn; i++) w[i] = 0;//这里用memset会TLE
scanf("%d%d", &n, &k);
for(int i = 1; i < n; i++){
int x, y;
scanf("%d%d", &x, &y);
E[x].push_back(y);
E[y].push_back(x);
}
for(int i = 1; i <= k; i++){
int x, y;
scanf("%d%d", &x, &y);
w[x] = y;
}
int L = 0, R = 1e9, ans;
while(L <= R){
int mid = (L+R)/2;
if(check(mid)) R = mid-1, ans = mid;
else L = mid+1;
}
printf("%d\n", ans);
}
return 0;
}