标签:cto namespace efi 题目 cin clear names scanf while
题:https://codeforces.com/contest/1241/problem/E
题目大意:给你一棵树,每一个点都可以染k种颜色,你拥有无数种颜色,每一种颜色最多使用2次,如果一条边的两个节点拥有同一种颜色,那么就说
这条边是饱和的,一个树的价值定义为饱和边的权值之和,问一棵树的最大价值是多少。
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back const int M=5e5+5; int head[M],tot,n,k; vector<ll>val; ll dp[M][2]; //dp[u][1] 表示这条边用了k种颜色了。 //dp[u][0] 表示这条边用了k-1种颜色。 struct node{ int v,nextt; ll w; }e[M<<1]; bool cmp(int x,int y){ return x>y; } void addedge(int u,int v,ll w){ e[tot].v=v; e[tot].w=w; e[tot].nextt=head[u]; head[u]=tot++; } void dfs(int u,int f){ dp[u][0]=dp[u][1]=0; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(v!=f){ dfs(v,u); dp[u][0]+=dp[v][1]; dp[u][1]+=dp[v][1]; } } val.clear(); for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(v!=f){//将当前的子节点降到只用了k-1种颜色的最优选择 val.pb(dp[v][0]+e[i].w-dp[v][1]); } } sort(val.begin(),val.end(),cmp); int len=val.size(); len=min(len,k); for(int i=0;i<len;i++){ if(val[i]<0) break; if(i<k-1) dp[u][0]+=val[i]; dp[u][1]+=val[i]; } } int main(){ int t; cin>>t; while(t--){ tot=0; scanf("%d%d",&n,&k); for(int i=0;i<=n;i++) head[i]=-1; for(int u,v,i=1;i<n;i++){ ll w; scanf("%d%d%I64d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } dfs(1,-1); printf("%I64d\n",max(dp[1][0],dp[1][1])); } return 0; }
标签:cto namespace efi 题目 cin clear names scanf while
原文地址:https://www.cnblogs.com/starve/p/11645076.html