http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1007&cid=883
题意:
给一个树,边权。有一个整数k,找树的子图G,满足:G内连通、度大于k的顶点个数不大于1、总权值要尽可能大。
解析:
对于每个点,维护 d o w n [ i ] down[i] down[i]表示往下选择 k − 1 k-1 k−1个儿子(儿子也最多选择 k − 1 k-1 k−1个)的最大权值。
接下来利用 d o w n down down维护出 u p up up数组,表示当前点为中心(可以大于K)时,上方所能得到的最大权值。
u p up up数组从上往下维护,对于一个点,假设儿子 u u u为中心,那么 u u u这条边一点要选了。其它的,可以在父亲或其它儿子中选出 K − 1 K-1 K−1个点。
做法是将所有 d o w n [ s o n ] + ∣ e d g e ∣ down[son]+|edge| down[son]+∣edge∣和 u p [ f a ] up[fa] up[fa]排序后选 K − 1 K-1 K−1个最大的,然后遍历每个儿子,判断如果选择了这个儿子则删去再加一个权值次大的。
代码:
/*
* Author : Jk_Chen
* Date : 2020-08-04-13.10.05
*/
#include
using namespace std;
#define LL long long
#define LD long double
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<"> "<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=2e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
#define rep_e(i,p,u) for(int i=head[p],u=to[i];i;i=nex[i],u=to[i])
int head[maxn],to[maxn<<1],nex[maxn<<1],val[maxn<<1],now;
void add(int a,int b,int v){
nex[++now]=head[a];head[a]=now;to[now]=b;val[now]=v;
}
/*_________________________________________________________edge*/
bool cmp(pill a,pill b){
return a.fi>b.fi;
}
int n,k;
bool vis[maxn];
LL up[maxn];
LL down[maxn];
LL ans[maxn];
pill tmp[maxn];
void dfs(int p,int fa){
rep_e(i,p,u){
if(u==fa)continue;
dfs(u,p);
}
int son=0;
rep_e(i,p,u){
if(u==fa)continue;
tmp[++son]={down[u]+val[i],u};
}
sort(tmp+1,tmp+1+son,cmp);
down[p]=0;
rep(i,1,min(son,k-2)){
down[p]+=tmp[i].fi;
}
}
void dfs2(int p,int fa){/// up[i]:点i为中心时,可以从上得到的权值
ans[p]=up[p];
rep_e(i,p,u){
if(u==fa)continue;
ans[p]+=down[u]+val[i];
}
/// deal up
if(k==2){
rep_e(i,p,u){
if(u==fa)continue;
up[u]=val[i];
dfs2(u,p);
}
return;
}
int son=0;
rep_e(i,p,u){
if(u==fa)continue;
vis[u]=0;
tmp[++son]={down[u]+val[i],u};
}
if(fa!=0){
tmp[++son]={up[p],fa};
}
sort(tmp+1,tmp+1+son,cmp);
LL S=0;
int Nex;
rep(i,1,k-2){
if(i>son)break;
S+=tmp[i].fi;
vis[tmp[i].se]=1;
Nex=i+1;
}
rep_e(i,p,u){
if(u==fa)continue;
if(vis[u]){
up[u]=S-(down[u]+val[i]);
if(Nex<=son)
up[u]+=tmp[Nex].fi;
}
else{
up[u]=S;
}
up[u]+=val[i];
}
rep_e(i,p,u){
if(u==fa)continue;
dfs2(u,p);
}
}
int t=rd;
int main(){
while(t--){
now=0;
n=rd;
k=rd+1;
rep(i,1,n){
head[i]=0;
}
rep(i,1,n-1){
int a=rd,b=rd,v=rd;
add(a,b,v);
add(b,a,v);
}
if(k<2){
puts("0");
continue;
}
dfs(1,0);
dfs2(1,0);
LL Ans=0;
rep(i,1,n){
Ans=max(Ans,ans[i]);
}
printf("%lld\n",Ans);
}
return 0;
}