Wannafly挑戰賽28 C msc的寵物
阿新 • • 發佈:2019-01-05
文章目錄
Wannafly挑戰賽28 msc的寵物
題意:
給定一棵樹,樹上每個節點有權值,要求刪除最多k條邊使得所有聯通塊的最大值和最小的差最大的最小
分析:
最小化最大值,很明顯是二分最大的差值D了
轉化一下題目其實就是將樹上的節點分成k個聯通塊,使得所有聯通塊的最大值和最小的差最大的最小。
狀態:
- f[x] 表示至少刪除F[x] 個才能使得x子樹差值不超過D
- g[x][u] 表示至少刪除g[x][u] 個才能使得子樹最大值為a[u]
狀態轉移:
設y是x的子節點
- 如果 a[y] <= a[u] <= a[y]+D,g[x][u] = min(f[y]+1,g[x][u]);(直接斷開這條邊或者留下這條邊)
- 否則g[x][u] = f[y]+1; (直接斷開這條邊)
- f[x] = min(g[x][u]);
參考程式碼
#include <bits/stdc++.h>
#define Pb push_back
using namespace std;
typedef long long LL;
// const int INF = 0x7FFFFFFF;
const LL INFF =1e15;
const int maxn = 1000+10;
LL f[maxn],g[maxn][maxn];
LL a[maxn];
LL val[maxn];
std::vector<int> G[maxn];
LL D;
int n,k;
void dfs(int node,int fa){
for(int i = 1;i <= n; ++i)
{
if(a[node] <= a[i] && a[i] <= a[node]+ D)
g[node][i] = 0;
else
g[node][i] = INFF;
}
for(int i = 0;i < (int) G[node].size();++i){
int v = G[node][i];
if(v == fa) continue;
dfs(v,node);
for(int u = 1;u <= n; ++u){
if(a[v] <= a[u] && a[u] <= a[v]+D)
g[node][u] += min(f[v]+1,g[v][u]);
else
g[node][u] += f[v]+1;
}
}
f[node] = INFF;
for(int i = 1;i <= n; ++i)
f[node] = min(f[node],g[node][i]);
}
LL check(LL mid){
D = mid;
dfs(1,-1);
// cout<<D<<" "<<f[1]<<endl;
// cout<<f[1]<<endl;
return f[1];
}
int main(void)
{
cin>>n>>k;
for(int i = 1;i <= n; ++i)
scanf("%lld",&a[i]);//,val[i] = a[i];
// sort(val+1,val+n+1);
for(int i = 1,v,u;i < n; ++i){
scanf("%d%d",&u,&v);
G[u].Pb(v);
G[v].Pb(u);
}
LL l = 0,r = 1000000000+2;
while(r >= l){
LL mid = (r+l)>>1;
if(check(mid) <= k)// < 說明差值可以縮小,> 說明差值過小
r = mid-1;
else
l = mid+1;
}
cout<<l<<endl;
return 0;
}