题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5682
题意:
选择一些节点的beautiful值,让所有边相连的两个端点的beatiful值的差的绝对值的最大值最小
题解:
一看到让最大值最小,或者最小值最大就应该想到二分法。
这样就能把问题变为判定性问题,往往能够在一定程度上降低算法的复杂度,并且效率还比较 高。
这题,二分完答案之后我们就能够根据叶子节点的取值范围递推出所有点的取值范围,如果所有节点的取值范围都不为空,则上限还能更小。
初始化:
有输入beautiful值得叶子节点范围为[x,x],剩下的都为[1,10^9]。
代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 5e4 + 10;
const int INF = 1e9;
struct Node {
int L, R;
int l, r;
}nds[maxn];
int n, k;
vector<int> G[maxn];
int _ans;
bool dfs(int u, int fa) {
nds[u].l = nds[u].L, nds[u].r = nds[u].R;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v == fa) continue;
if (!dfs(v, u)) return false;
nds[v].l = max(1, nds[v].l - _ans);
nds[v].r = min(INF, nds[v].r + _ans);
nds[u].l = max(nds[u].l, nds[v].l);
nds[u].r = min(nds[u].r, nds[v].r);
if (nds[u].l > nds[u].r) return false;
}
return true;
}
void init() {
for (int i = 1; i <= n; i++) {
nds[i].L = 1;
nds[i].R = INF;
G[i].clear();
}
}
int main() {
int tc;
scanf("%d", &tc);
while (tc--) {
scanf("%d%d", &n, &k);
init();
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = 0; i < k; i++) {
int p, v;
scanf("%d%d", &p, &v);
nds[p].L = nds[p].R = v;
}
int l = -1, r = INF;
while (l < r - 1) {
_ans = l + (r - l) / 2;
if (dfs(1,-1)) r = _ans;
else l=_ans;
}
printf("%d\n", r);
}
return 0;
}