hdu_6820 Tree
树形dp裸题
两遍dfs
第一次求dp[i][0]表示选取k-1条边(除父节点外)所能取得的最大权值
第二次求dp[i][1]表示i点可以超过k条边其他点不行所能取得的最大权值,过程中更新父亲的dp[fa][0]
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
#define ll long long
struct sons{ll dp;int id;};
struct edge{int v;ll w;};
vector<edge> G[200010];
int p[200010],n,k,T;
ll dp[200010][2],ans;
void init(){
for(int i=1;i<=n;i++){G[i].clear(); dp[i][0]=dp[i][1]=0;}
ans=0;
}
bool cmp1(ll x,ll y){return x>y;}
bool cmp(sons x,sons y){return x.dp>y.dp;}
void dfs(ll u){
ll son[G[u].size()+10]; int cnt=0;
for(int i=0;i<G[u].size();i++)if(G[u][i].v!=p[u]){
int v=G[u][i].v; ll w=G[u][i].w;
p[v]=u;
dfs(v);
son[++cnt]=dp[v][0]+w;
}
if(!cnt)return;
sort(son+1,son+cnt+1,cmp1);
for(int i=1;i<=min(cnt,k-1);i++)dp[u][0]+=son[i];
}
void dfs2(ll u){
sons son[G[u].size()+10];int cnt=0;
for(int i=0;i<G[u].size();i++){
int v=G[u][i].v; ll w=G[u][i].w;
if(G[u][i].v!=p[u])son[++cnt].dp=dp[v][0]+w;
else son[++cnt].dp=dp[v][0]-dp[u][0];
son[cnt].id=v;
}
if(!cnt)return;
sort(son+1,son+cnt+1,cmp);
for(int i=1;i<=cnt;i++)dp[u][1]+=son[i].dp;
dp[u][0]=0;
for(int i=1;i<=min(cnt,k-1);i++)dp[u][0]+=son[i].dp;
//prllf("%d:%d %d\n",u,dp[u][0],dp[u][1]);
ans=max(ans,dp[u][1]);
for(int i=1;i<=cnt;i++)if(son[i].id!=p[u]){
if(i<k){if(k<=cnt)dp[u][0]+=son[k].dp;}
else dp[u][0]+=son[i].dp;
//prllf("%d:%d %d\n",u,dp[u][0],dp[u][1]);
dfs2(son[i].id);
if(i<k){if(k<=cnt)dp[u][0]-=son[k].dp;}
else dp[u][0]-=son[i].dp;
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<n;i++){
int u,v;ll w;
scanf("%d%d%lld",&u,&v,&w);
G[u].push_back((edge){v,w});
G[v].push_back((edge){u,w});
}
if(k==0){printf("0\n"); init(); continue;}
dfs(1);
dfs2(1);
//for(ll i=1;i<=n;i++)prllf("%d %d\n",dp[i][0],dp[i][1]);
printf("%lld\n",ans);
init();
}
return 0;
}

浙公网安备 33010602011771号