洛谷P3177||bzoj4033 [HAOI2015]树上染色

洛谷P3177

bzoj4033

根本不会做。。。

上网查了题解,发现只要在状态定义的时候就考虑每一条边全局的贡献就好了?

考虑边的贡献和修改状态定义我都想到了,然而并不能想到要结合起来

ans[i][j]表示i子树中选j个黑色节点,最大的贡献和

容易知道:每一条边的贡献为 长度*(边一侧的白点数*边另一侧的白点数+边一侧的黑点数*边另一侧的黑点数)

可以发现,如果已经确定一棵子树中选多少个黑点,那么这棵子树的根到其父亲的连边的贡献可以直接确定

考虑向一棵树的根节点(u)下再加入一棵子树(v)时的转移:sz[u]表示u子树的节点个数

$ans[u][k]=max{ans[u][i]+ans[v][j]+dis(u,v)*(j*(K-j)+(sz[v]-j)*(n-sz[v]-K+j))}(k=i+j)$

要构建一棵树,可以先构建完所有以根节点的某个子节点为根的子树,然后再依次将子树与根节点连上边。

复杂度好像是n^3的?事实上只要改一下循环的上界就n^2了。转移某个子树时,i上界为之前已经转移过的子树size和 + 1(根节点自身),j上界为目标子树size

可以发现,树上每一对点对刚好产生1次转移(在lca处产生),因此总复杂度等于总点对数是n^2的

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 #define fi first
 7 #define se second
 8 #define mp make_pair
 9 #define pb push_back
10 typedef long long ll;
11 typedef unsigned long long ull;
12 struct E
13 {
14     ll to,nxt,d;
15 }e[4010];
16 ll f1[2010],ne;
17 ll ans[2010][2010];
18 ll sz[2010];
19 ll tmp[2010];
20 ll n,K;
21 void dfs(ll u,ll fa)
22 {
23     ans[u][0]=ans[u][1]=0;sz[u]=1;
24     ll i,j;
25     for(ll v,k=f1[u];k;k=e[k].nxt)
26         if(e[k].to!=fa)
27         {
28             v=e[k].to;
29             dfs(v,u);
30             memset(tmp,192,sizeof(ll)*(sz[u]+sz[v]+1));
31             for(i=sz[u];i>=0;--i)
32             {
33                 for(j=sz[v];j>=0;--j)
34                 {
35                     if(K>=j&&n-sz[v]-K+j>=0)
36                     {
37                         tmp[i+j]=max(tmp[i+j],ans[u][i]+ans[v][j]
38                             +e[k].d*(j*(K-j)+(sz[v]-j)*(n-sz[v]-K+j)));
39                     }
40                 }
41             }
42             for(i=0;i<=sz[u]+sz[v];++i)
43                 ans[u][i]=tmp[i];
44             sz[u]+=sz[v];
45         }
46     //printf("1t%lld
",u);
47     //for(i=0;i<=sz[u];i++)
48     //    printf("%lld %lld
",i,ans[u][i]);
49 }
50 int main()
51 {
52     ll i,x,y,z;
53     memset(ans,192,sizeof(ans));
54     scanf("%lld%lld",&n,&K);
55     for(i=1;i<n;++i)
56     {
57         scanf("%lld%lld%lld",&x,&y,&z);
58         e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;
59         e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;e[ne].d=z;
60     }
61     dfs(1,0);
62     printf("%lld",ans[1][K]);
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/hehe54321/p/9846662.html