传送门
题意:给出一棵树,选择若干条边使边权值和最大,要求每个结点至多被k条边覆盖
题解:(感觉做E题不那么吃力了)
树形dp。考虑子结点与父节点的关系可知有两种情况,一种情况子结点已经连完k条边则不可以与父节点连边,另一种是留一条边和父节点相连,所以可以很容易想到用dp[0][u]表示选择k条当前结点和子节点的边得到的以u为结点的子树最大值,dp[1][u]表示选择k-1条当前结点和子节点的边得到的以u为结点的子树最大值,与子树相连的边可以用优先队列维护
#include<bits/stdc++.h>
using namespace std;
#define debug(x) cout<<#x<<" is "<<x<<endl;
typedef long long ll;
const int maxn=5e5+5;
struct edge{
int fr;
int to;
ll val;
int nex;
}e[maxn<<1];
int head[maxn],cnt,n,k;
ll dp[2][maxn],ans;
void adde(int x,int y,ll z){
e[cnt].fr=x;
e[cnt].to=y;
e[cnt].val=z;
e[cnt].nex=head[x];
head[x]=cnt++;
}
void dfs(int u,int f){
priority_queue<ll>pq;
ll x=0;
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v==f)continue;
dfs(v,u);
x+=dp[0][v];
if(dp[1][v]+e[i].val-dp[0][v]>0)pq.push({dp[1][v]+e[i].val-dp[0][v]});
}
//ll x=0;
int w=1;
while(!pq.empty()&&w<k){
ll xx=pq.top();
pq.pop();
x+=xx;
w++;
}
dp[0][u]=dp[1][u]=x;
if(!pq.empty())dp[0][u]+=pq.top();
ans=max(ans,max(dp[1][u],dp[0][u]));
/* debug(u);
debug(dp[0][u]);
debug(dp[1][u]);*/
}
int main(){
int q;
scanf("%d",&q);
while(q--){
// int n,k;
cnt=0;
ans=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
head[i]=-1;
dp[0][i]=dp[1][i]=0;
}
for(int i=1;i<n;i++){
int a,b;
ll c;
scanf("%d%d%lld",&a,&b,&c);
adde(a,b,c);
adde(b,a,c);
}
dfs(1,0);
printf("%lld\n",ans);
}
return 0;
}