P3177 [HAOI2015] 树上染色

/*
一棵树 用0-k的val去染色 将k个染成black,n-k个染成white 
定义 收益为 任意两个 同色的point 之间的dis 之和 求收益最大是多少

直接任意枚举两个点的颜色 求 dis=abs(dep[u]-dep[v]) 
->对于每一条边来说 tot=w[u->v]*( num_k[v]*(K-num_k[v])+(siz[v]-num_k[v])*(n-K-size[v]+num_k[v]) )
def:f[u][i][k]->以u为root的前i个子树有k个black 收益最大值

f->-1(叶节点)   k:min(size[u],K)->0  kk:0->min(size[v],k)
u->v f[u][i][k]=max(f[u][i][k],f[u][i-1][k-kk]+f[v][size_son_v][kk]+tot)     滚掉第一维                  
:::在转折点i-1->i 滚掉后f[u][i][k]=max(f[u][i-1][k],f[u][i-1][k-kk]+.......)
:::f[u][i-1][k]不一定<=f[u][i-1][k-kk]+....所以可能用f[][i-1]更新
:::所以要正序
:::判断是否 都是合法状态 size_son_v数量 不全相同
*/
/*
3 1
1 2 1
1 3 2

3
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
#define ll long long
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=2e3 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

inline int read(){
    int res=0,f=1;char ch=getchar();
    while(isdigit(ch)==0){ if(ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)){ res=res*10+ch-'0';ch=getchar();}
    return f*res;
}
int n,K,head[maxn],to[maxn<<1],nxt[maxn<<1],w[maxn<<1],tot,siz[maxn] ;
ll f[maxn][maxn];

void add(int a,int b,int val){
    to[++tot]=b,nxt[tot]=head[a],head[a]=tot,w[tot]=val;
}

void dfs(int u,int fa)
{
    siz[u]=1;f[u][1]=f[u][0]=0;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];if(v==fa) continue;
        dfs(v,u); siz[u]+=siz[v];
        
        for(int j=min(K,siz[u]);j>=0;j--)
        {
            for(int k=0;k<=min(j,siz[v]);k++)
            {
                if(f[u][j-k]==-1) continue;
                ll tmp=(ll)w[i]*( k*(K-k)+(siz[v]-k)*(n-K-siz[v]+k) );
                f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+tmp);
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    memset(f,-1,sizeof(f));
    n=read(),K=read();
    for(int i=1;i<=n-1;i++){
        int a,b,c;
        a=read(),b=read(),c=read();
        add(a,b,c),add(b,a,c);
    }
    dfs(1,0);
    
    cout<<f[1][K]<<'\n';
    
    return 0;
}

 

posted @ 2023-11-12 11:03  JMXZ  阅读(6)  评论(0)    收藏  举报