(二分+树形dp)wannafly28-C

https://ac.nowcoder.com/acm/contest/217/C
msc有n个小宠物,这些宠物的家是连在一起的,更有趣的是,这些宠物的家之间的连接关系形成了一个树的形态。
每个小宠物的习性是不太一样的,比如说有的可能吃素,有的可能吃荤。
作为直觉系女生,msc凭着自己突出的直觉对每个小宠物都有一个关于习性的评估值,对于宠物i,它的评估值是a[i]。
考虑到习性差异过大会很难伺候,甚至宠物间会发生冲突,所以msc希望去掉至多k个连接关系使得任意两个可以互相到达的宠物间的评估值的差的最大值尽量小。
两个宠物(x,y)可以互相到达当且仅当存在一个序列s1,s2,…,sk-1,sk使得对于1 ≤ i < k,si与si+1之间相连且s1=x,sk=y
现在msc给出了n个小宠物的评估值a[1…n]和这棵树的形态,msc希望你帮她求出去掉至多k个连接关系之后,任意两个可以互相到达的宠物间的评估值的差的最大值最小是多少。
参考博客地址

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 10;
int ai[maxn];
vector<int> E[maxn];
int n, k, t;
int f[maxn][maxn], g[maxn];
void dp(int x, int fa = 0) {
    for(register int i = 1; i <= n; i++) 
        if(ai[x] >= ai[i] && ai[x] <= (ll)ai[i] + t) f[x][i] = 0;
    for(int v : E[x]) if(v != fa) {
        dp(v, x);
        for(register int i = 1; i <= n; i++) f[x][i] += min(f[v][i], g[v] + 1);
    }
    for(register int i = 1; i <= n; i++) g[x] = min(g[x], f[x][i]);
}
int chk() {
    memset(f, 127 / 3, sizeof(f));
    memset(g, 127 / 3, sizeof(g));
    dp(1);
    return g[1];
}
int main()
{
    scanf("%d%d", &n, &k);
    for(register int i = 1; i <= n; i++) scanf("%d", &ai[i]);
    for(register int i = 1, a, b; i < n; i++) {
        scanf("%d%d", &a, &b);
        E[a].push_back(b);
        E[b].push_back(a);
    }
    ll l = 0, r = 2e9;
    while(l < r) {
        ll m = (l + r) >> 1;
        t = m;
        if(chk() > k) l = m + 1;
        else r = m;
    }
    printf("%lld\n", l);
}

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/83933510