解析
本题的关键是选取哪一个根对答案没有影响
还有一个重要的性质是:根节点必定涂色
这点对每棵子树作为独立的子问题时依然成立
然鹅我完全没有看到上面那俩性质
直接暴力设计dp状态0.、1、2 开始莽
然后?然后就T了啊…
只好开始考虑换根
然后?然后就WA了啊…
最后捯饬到第四交才过
qwq
有一点可贵是忍住了没看LOJ的数据吧
看到题不要被它的描述迷惑
先想想有啥性质
先好好想清楚性质再敲,不要硬用min交给代码莽!
(尽管最后莽出来了)
代码
其实不用换根但是换都换了不贴太可惜了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
const double eps=1e-6;
inline ll read() {ll x=0,f=1;char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return f*x;
}
int n,m,k;
struct node{int to,nxt;
}p[N<<1];
int fi[N],cnt=-1;
inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
}
int dp[N][3],c[N],up[N][3];
void dfs1(int x,int f){if(x<=m){dp[x][c[x]]=0;dp[x][3-c[x]]=2e4;dp[x][0]=1;return;}dp[x][0]=dp[x][1]=dp[x][2]=0;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs1(to,x);dp[x][0]+=dp[to][0];dp[x][1]+=min(dp[to][0],dp[to][1]);dp[x][2]+=min(dp[to][0],dp[to][2]);}dp[x][0]=min(dp[x][0],min(dp[x][1],dp[x][2])+1);return;
}
void dfs2(int x,int f){if(f){up[x][0]=up[f][0]+dp[f][0]-min(dp[x][1],dp[x][2])-1;up[x][1]=min(up[f][0],up[f][1])+dp[f][1]-min(dp[x][0],dp[x][1]);up[x][2]=min(up[f][0],up[f][2])+dp[f][2]-min(dp[x][0],dp[x][2]);}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs2(to,x);}return;
}
int ans=2e9;
int main(){memset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();for(int i=1;i<=m;i++) c[i]=read(),c[i]++;for(int i=1;i<n;i++){int x=read(),y=read();addline(x,y);addline(y,x);}dfs1(m+1,0);dfs2(m+1,0);for(int i=m+1;i<=n;i++){//printf("i=%d dp=%d up=%d\n",i,dp[i][0],up[i][0]);ans=min(ans,dp[i][0]+up[i][0]);}printf("%d\n",ans);
}
/*
8 6
1 1 0 1 1 0
1 7
2 7
3 7
7 8
4 8
5 8
6 8
*/