1. 程式人生 > >牛客挑戰賽28 C.msc的寵物

牛客挑戰賽28 C.msc的寵物

題意: 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個連線關係之後,任意兩個可以互相到達的寵物間的評估值的差的最大值最小是多少。

|a[i]|≤1000000000

1≤k+1≤n≤1000

題解:

二分答案dfs check(mid),f[x][y]表示x子樹裡與x相連的聯通塊每個點都在[a[y],a[y]+mid]需要切幾條邊,f[x]表示只考慮處理x子樹需要切幾條邊

#include<bits/stdc++.h>
#define pb push_back
#define sc(x) scanf("%d",&x)
#define sll(x) scanf("%lld",&x)
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e3+10;
vector<int> to[maxn];
int n, k, a[maxn], f[maxn][maxn], g[maxn];

void dfs(int u, int fa, LL x){
	for(int i=1;i<=n;i++) f[u][i]=(a[u]>=a[i]&&a[u]<=a[i]+x)?0:INF;
	for(int v: to[u]) if(v!=fa){
		dfs(v,u,x);
		for(int i=1;i<=n;i++) f[u][i]+=min(f[v][i],g[v]+1);
	}
	for(int i=1;i<=n;i++)g[u]=min(g[u],f[u][i]);
}
int check(LL x){
	memset(g,INF,sizeof(g));
	dfs(1,1,x);
	return g[1];
}

int main(){
	sc(n); sc(k);
	for(int i=1;i<=n;i++) sc(a[i]);
	for(int i=1;i<n;i++){
		int u,v; sc(u); sc(v);
		to[u].pb(v); to[v].pb(u);
	}
	LL L=-1,R=INF*2;
	while(L+1<R){
		LL mid=(L+R)>>1;
		if(check(mid)>k) L=mid;
		else R=mid;
	}
	printf("%lld\n",R);
	return 0;
}