http://acm.hdu.edu.cn/showproblem.php?pid=6820
树形DP裸题,不知道为啥过得不是很多,可能都被前期题卡住了没看这题
sumkj1[v]表示以v为根节点选k-1个子节点并且全部满足度数不超过k的最大连通块的边权和
sum[v]=sumkj1[v]+e[u][v].l,也就是包含一条连向父亲的节点
这个用一遍dfs就能处理出来,每次排个序取最大的k-1个子节点
第二遍dfs求把父节点fa当做子树到u的满足条件的最大连通块的边权和存到u所连向的点的g[v,l]中,其中 l 表示v子树的最大值
然后我们假设把u当那个超过k的,也就是把g[u]中所有的子节点的l加起来,更新一下最大值
最后枚举u的每个子节点v,算出对应的nfmx,也就是v把u当子节点的满足条件的最大边权和,传递给v
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=2e5+10;
int n,k;
ll ans;
struct ed
{
int to;ll l;
bool operator < (const ed &b)const
{
return l>b.l;
}
};
vector<ed> e[maxl],g[maxl];
ll sumkj1[maxl],sum[maxl];
inline void prework()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
e[i].clear(),g[i].clear();
int u,v,l;
for(int i=1;i<=n-1;i++)
{
scanf("%d%d%d",&u,&v,&l);
e[u].push_back(ed{v,l});
e[v].push_back(ed{u,l});
}
}
inline void dfs1(int u,int fa)
{
int v;
for(ed ee:e[u])
{
v=ee.to;
if(v==fa) continue;
dfs1(v,u);
sum[v]=ee.l+sumkj1[v];
g[u].push_back(ed{v,sum[v]});
}
sort(g[u].begin(),g[u].end());
int len=g[u].size();len=min(len,k-1);
sumkj1[u]=0;
for(int i=0;i<len;i++)
sumkj1[u]+=g[u][i].l;
}
inline void dfs2(int u,int fa,ll fmx)
{
if(fa!=0)
g[u].push_back(ed{fa,fmx});
sort(g[u].begin(),g[u].end());
int v,len=g[u].size(),up=min(len,k);
ll tmp=0,nfmx;
for(int i=0;i<len;i++)
tmp+=g[u][i].l;
ans=max(ans,tmp);
tmp=0;
for(int i=0;i<up;i++)
tmp+=g[u][i].l;
for(int i=0;i<len;i++)
{
v=g[u][i].to;
if(v==fa) continue;
if(i<up)
nfmx=tmp-sum[v]+(sum[v]-sumkj1[v]);
else
nfmx=tmp-g[u][k-1].l+(sum[v]-sumkj1[v]);
dfs2(v,u,nfmx);
}
}
inline void mainwork()
{
ans=0;
if(k==0) return;
dfs1(1,0);
dfs2(1,0,0);
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}