码迷,mamicode.com
首页 > 其他好文 > 详细

[HAOI2015]树上染色

时间:2019-10-04 20:30:53      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:并集   continue   stdin   lin   eof   define   flag   std   现在   

我们用贡献法考虑一条边会被算多少次

我们可能会设为\(f_{i,j,k}\)表示以\(i\)为根,前\(j\)个儿子,选\(k\)个黑点,对现在前j个子树所在集合的最大贡献

但这样我们合并集合的时候,我们漏计算了原小集合的边到大集合的贡献,

因此设为以\(i\)为根子树,前\(j\)个儿子,选\(k\)个黑点对整棵树的最大贡献

这样一条边会在第一次用他合并时就计算时就算出它对最终答案贡献

注意一下\(size\)合并位置

#include<bits/stdc++.h>
#define re register
#define INF 0x3f3f3f3f3f3f3f3f
#define N 2005
using namespace std;
template<typename _ll>
inline void read(re _ll& x){
    re char opt;re _ll flag=1,res=0;
    while((opt=getchar())<'0'||opt>'9')if(opt=='-')flag=-1;
    while(opt>='0'&&opt<='9'){res=(res<<3)+(res<<1)+opt-'0';opt=getchar();}
    x=res*flag;
}
typedef long long ll; 
struct Edge{
    ll to,next,v;
}e[N<<1];
ll dp[N][N],n,K,cnt,h[N],size[N];
inline void AddEdge(re ll x,re ll y,re ll z){e[++cnt]=(Edge){y,h[x],z};h[x]=cnt;}
inline void tree_pack(re ll x,re ll prt){
    re ll i,j,k,y;size[x]=1;
    dp[x][1]=*dp[x]=0;
    for(i=h[x];i;i=e[i].next){
        y=e[i].to;if(y==prt)continue;
        tree_pack(y,x);
        size[x]+=size[y];
        for(j=min(size[x],K);j>=0;--j)
            for(k=0;k<=min(j,size[y]);++k)
                dp[x][j]=max(dp[x][j],dp[y][k]+dp[x][j-k]+e[i].v*(k*(K-k)+(size[y]-k)*(n-size[y]-K+k)));
    }
}
inline void Read(void){
    re ll i,x,y,z;
    read(n);read(K);
    for(i=1;i<n;++i){read(x);read(y);read(z);AddEdge(x,y,z);AddEdge(y,x,z);}
}
int main(void){
//  freopen("income.in","r",stdin);
//  freopen("income.out","w",stdout);
    memset(dp,0xc0,sizeof dp);
    Read();
    tree_pack(1,0);
    printf("%lld\n",dp[1][K]);
    return 0;
}
/*
3 1
1 2 1
1 3 2
*/

[HAOI2015]树上染色

标签:并集   continue   stdin   lin   eof   define   flag   std   现在   

原文地址:https://www.cnblogs.com/66t6/p/11622918.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!