给出了一个由n个顶点组成的加权树。回想一下,树是一个没有圈的连通图。顶点ui和vi通过带权重wi的边连接。

让我们将树的k-着色定义为每个顶点的k-着色,这样每个颜色的使用次数就不会超过两次。你可以假设你有无限多的颜色可用。我们说,如果一条边的端点共享至少一种颜色(即存在一种指定给两个端点的颜色),那么它在给定的k-着色中是饱和的。

我们还将k-着色的值定义为饱和边的权重之和。

请计算给定树的k-着色的最大可能值。

你必须回答与q无关的问题。

第一行包含一个整数q(1≤q≤5⋅105)-查询数。

每个查询的第一行包含两个整数n和k(1≤n,k≤5⋅105)-树中的顶点数和分配给每个顶点的颜色数。

/*
 * cf1223E
 * 题意:
 * 给出一棵树,选择若干条边使边权值和最大,要求每个节点至多被k条边覆盖
 * 题解:
 * 树形dp。
 * 考虑子节点和父节点的关系可知有两种情况:
 * (1)子节点已经连完k条边则不可以与父节点连边。
 * (2)子节点留一条边和父节点连边。
 * 可以用dp[0][u]表示选择k条当前节点与子节点的边得到的以u为节点的子树的最大值
 * dp[1][u]表示选择k-1条当前节点与子节点的边得到的以u为节点的子树的最大值,与子树相连的边可以用优先队列维护
 */
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+2;
struct node {
    int u,v,next;
    ll w;
}edge[maxn<<1];
int head[maxn],tot;
int N,K;
ll dp[2][maxn],ans;
void addedge (int u,int v,ll w) {
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
inline void dfs (int u,int pre) {
    priority_queue<ll> q;
    ll x=0;
    for (int i=head[u];i!=-1;i=edge[i].next) {
        int v=edge[i].v;
        if (v==pre) continue;
        dfs(v,u);
        x+=dp[0][v];
        if (dp[1][v]+edge[i].w-dp[0][v]>0)
            q.push({dp[1][v]+edge[i].w-dp[0][v]});
    }
    ll w=1;
    while (!q.empty()&&w<K) {
        ll t=q.top();
        q.pop();
        x+=t;
        w++;
    }
    dp[0][u]=dp[1][u]=x;
    if (!q.empty()) dp[0][u]+=q.top();
    ans=max(ans,max(dp[1][u],dp[0][u]));
}
int main () {
    int Q;
    scanf("%d",&Q);
    while (Q--) {
        ans=0;
        tot=0;

        scanf("%d%d",&N,&K);
        for (int i=0;i<=N;i++) {
            dp[1][i]=0;
            dp[0][i]=0;
            head[i]=-1;
        }
        for (int i=1;i<N;i++) {
            int u,v;ll w;
            scanf("%d%d%lld",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dfs(1,0);
        printf("%lld\n",ans);
    }
}

 

接下来的n-1行中的每一行描述树的一个边。边i由三个整数ui、vi和wi(1≤ui,vi≤n,ui≠vi,1≤wi≤105)表示-它连接的顶点的标签和边的权重。可以保证给定的边形成一棵树。

保证所有查询的n和不超过5⋅105。

对于每个查询,打印一个整数-给定树的k-着色的最大值。