题目
给一棵m(m<=1e4)个结点的无根树,你可以选择一个度数大于1的结点作为根,
然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。
你的着色方案应该保证,根结点到每个叶子的简单路径上,
都至少包含一个有色结点(哪怕是这个叶子本身)。
题目给出一个n(n<=5021),保证[1,n]均为叶子结点
对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色。
给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。
输出最少的着色节点的个数。
思路来源
乱搞AC
https://www.cnblogs.com/neighthorn/p/6188302.html
题解
在换根dp专题里,就写了换根dp,但是写完发现自己非常sb
dp[u]维护的是这个点u能使得儿子v减少多少个染色的点,
所有的dp[u]之和即为所有能减少的和,n-maxsumdp[u]即为所求,
对于一棵子树u的所有子节点v来说,贪心地对u进行染色,
如果v中黑色比白色多,则染成黑色;如果少就染成白色;否则染成万能节点,表示可黑可白
然后暴力换根,u为根换成v为根的时候,变化的只是二者的黑儿子、白儿子、万能儿子的个数,
也因此带来了u和v这两个点的颜色变化,和减少的dp值的变化,别的点均不变,返祖时换回来
但是,注意到这道题中有一个性质,即选根为哪个点是不影响答案的
对于相邻的两个点(u,v)来说,二者颜色不同的话两个着色点都需要保留,
二者颜色相同的话一定会少着色一个,所以对答案没有影响,随便选个根从底往上dp即可
代码
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef pair<int,int> P;
typedef long long ll;
const int N=1e4+10;//INF=0x3f3f3f3f;
vector<int>e[N];
bool ok[N];
int b[N],w[N],same[N];
int rt,n,m,u,v,sz[N],dp[N],col[N];
int res,ans;
void dfs(int u,int fa){
sz[u]=ok[u];
for(auto &v:e[u]){
if(v==fa)continue;
dfs(v,u);
sz[u]+=sz[v];
if(col[v]==0)b[u]++;
else if(col[v]==1)w[u]++;
else if(col[v]==2)same[u]++;
}
if(b[u]>w[u]){
col[u]=0;
dp[u]=b[u]+same[u]-1;
}
else if(b[u]<w[u]){
col[u]=1;
dp[u]=w[u]+same[u]-1;
}
else{
col[u]=2;
dp[u]=w[u]+same[u]-1;
}
ans+=dp[u];
}
void dfs2(int u,int fa){
res=max(res,ans);
for(auto &v:e[u]){
if(v==fa)continue;
if(v<=m)continue;
int pcu=col[u],pdpu=dp[u],pbu=b[u],pwu=w[u],psu=same[u];
int pcv=col[v],pdpv=dp[v],pbv=b[v],pwv=w[v],psv=same[v];
int pans=ans;
if(col[v]==0)b[u]--;
else if(col[v]==1)w[u]--;
else if(col[v]==2)same[u]--;
sz[u]-=sz[v];
ans-=dp[u];
if(b[u]>w[u]){
col[u]=0;
dp[u]=b[u]+same[u]-1;
}
else if(b[u]<w[u]){
col[u]=1;
dp[u]=w[u]+same[u]-1;
}
else{
col[u]=2;
dp[u]=w[u]+same[u]-1;
}
ans+=dp[u];
if(col[u]==0)b[v]++;
else if(col[u]==1)w[v]++;
else if(col[u]==2)same[v]++;
sz[v]+=sz[u];
ans-=dp[v];
if(b[v]>w[v]){
col[v]=0;
dp[v]=b[v]+same[v]-1;
}
else if(b[v]<w[v]){
col[v]=1;
dp[v]=w[v]+same[v]-1;
}
else{
col[v]=2;
dp[v]=w[v]+same[v]-1;
}
ans+=dp[v];
dfs2(v,u);
col[u]=pcu,dp[u]=pdpu,b[u]=pbu,w[u]=pwu,same[u]=psu;
col[v]=pcv,dp[v]=pdpv,b[v]=pbv,w[v]=pwv,same[v]=psv;
ans=pans;
}
}
int main(){
scanf("%d%d",&n,&m);
res=ans=0;
for(int i=1;i<=m;++i){
scanf("%d",&col[i]);
if(col[i]==0)b[i]++;
else w[i]++;
ok[i]=1;
}
for(int i=1;i<n;++i){
scanf("%d%d",&u,&v);
e[u].pb(v);
e[v].pb(u);
}
rt=m+1;
dfs(rt,-1);
// for(int i=1;i<=n;++i){
// printf("i:%d b:%d w:%d same:%d col:%d dp:%d\n",i,b[i],w[i],same[i],col[i],dp[i]);
// }
// printf("ans:%d\n",ans);
dfs2(rt,-1);
printf("%d\n",m-res);
return 0;
}