題意
在一顆有點權的樹上,選若干個點,使得這些點兩兩距離大於k,且點權和最大
思路
貪心的取比較大的值即可
將所有點按照深度從大到小排序,如果當前點點權\(a[i]\)大於0,則將距離為k以內的所有點減\(a[i]\)
代表取了當前點,為答案貢獻\(a[i]\)
如果下面又掃到大於零的點權,說明那個點比這個大,於是取那個
復雜度\(O(n^2)\)
代碼
int n,k;
int a[maxn],b[maxn];
vector<int>v[maxn];
int ans;
int dep[maxn];
void dfs(int x, int fa, int dp){
dep[x]=dp;
for(int i = 0; i < (int)v[x].size(); i++){
int y = v[x][i];
if(y==fa)continue;
dfs(y,x,dp+1);
}
}int vis[maxn];
int gao(int st){
for(int i = 1; i <= n; i++)vis[i]=0;
queue<PI>q;
q.push(make_pair(st,0));
int C = a[st];
while(!q.empty()){
int x = q.front().fst;
vis[x]=1;
a[x]-=C;
int stp = q.front().sc;
q.pop();
if(stp!=k){
for(int i = 0; i < (int)v[x].size(); i++){
int y = v[x][i];
if(!vis[y])q.push(make_pair(y,stp+1));
}
}
}
return C;
}
bool cmp(int a, int b){return dep[a]>dep[b];}
int main(){
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);b[i]=i;
}
for(int i = 1; i < n; i++){
int x,y;
scanf("%d %d", &x, &y);
v[x].pb(y);v[y].pb(x);
}dfs(1,-1,0);
sort(b+1,b+1+n,cmp);
for(int i = 1; i <= n; i++){
if(a[b[i]]>0)ans+=gao(b[i]);
//printf(" %d %d\n",b[i],ans);
}
printf("%d\n",ans);
return 0;
}
