msc的宠物 二分+树形DP
https://ac.nowcoder.com/acm/contest/7016/E
这题真没想到
考虑一个问题,删除边对极差的影响,-------无论如何删除边都有办法不让让答案变大(可能相等)
利用二分答案,每次算出mid都跑一次dp看看能不能k条边以内完成,dp[x][i]表示以x为根的子树,所有点的数值在list[i] -- list[i] + mid之间最少删除dp[x][i]个边
ans[x]表示ans[x]极差在mid之间最少删除ans[x] t条边
具体在代码
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 2000+11;
typedef long long ll;
ll inf = 1e15;
ll mid;
ll dp[maxn][maxn];
ll list[maxn];
vector<int>G[maxn];
void add(int x,int y){
G[x].push_back(y);
}
int n,k;
ll ans[maxn];
int dfs(int x,int fa){
//cout<<x<<endl;
for(int i = 1;i<=n;i++){
if(list[x] >= list[i] && list[i] + mid >= list[x]){
dp[x][i] = 0;
}
else{
dp[x][i] = inf;
}
}
for(int i=0;i<G[x].size();i++){
int p = G[x][i];
if(p == fa) continue;
dfs(p,x);
for(int j=1;j<=n;j++){
dp[x][j] += min(dp[p][j],ans[p] + 1);
}
}
for(int i = 1;i<=n;i++){
ans[x] = min(ans[x],dp[x][i]);
}
return 0;
}
int jude(){
for(int i=0;i<=n;i++){
ans[i] = inf;
}
dfs(1,-1);
return (ans[1] <= k);//可行
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
ans[i] = inf;
scanf("%lld",&list[i]);
}
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
ll l = 0;
ll r = 2e9+7;
ll cns = 0;
for(int i=0;i<111;i++){
mid = (l+r)/2;
if(jude()){//可以,区间加大
cns = mid;
r = mid - 1;
}
else{
l = mid + 1;
}
}
printf("%lld\n",cns);
return 0;
}
寻找真正的热爱

浙公网安备 33010602011771号