【題目大意】
給一棵n(<=200000)個節點的樹,每個點爲黑色或白色,一次操作可以使一個相同顏色的連通塊變成另一種顏色,求使整棵樹變成一種顏色的最少操作數
【解題思路】
先將相同顏色的連通塊縮點,然後我們就得到了一棵黑白相間的樹。
我們可以發現當確定一個點爲根時的最少操作數爲樹的高度減一。
當以樹的直徑的中點爲根時樹的高度最小。
因此答案爲(樹的直徑長度+1)/2。
用dp或者兩次dfs求出樹的直徑。
【呆馬】
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
using namespace std;
const int N=200001;
struct st{int to,next;} e[2][N<<1];
int n,num,i,j,x,y,p,ans,mxd,b[N],c[N],f[2][N],cnt[2];
void add(int x,int y,int t){e[t][++cnt[t]].to=y,e[t][cnt[t]].next=f[t][x],f[t][x]=cnt[t];}
void dfs(int x,int fa,int t,int flag,int d)
{
for (int i=f[t][x];i;i=e[t][i].next)
if (e[t][i].to!=fa)
{
int y=e[t][i].to;
b[y]=c[y]==c[x]?b[x]:++num;
dfs(y,x,t,flag,d+1);
}
if (flag==1 && d>mxd) mxd=d,p=x;
if (flag==2) ans=max(ans,d);
}
int main()
{
scanf("%d\n",&n);
for (i=1;i<=n;i++) scanf("%d",&c[i]);
for (scanf("\n"),i=1;i<n;i++) scanf("%d%d\n",&x,&y),add(x,y,0),add(y,x,0);
b[1]=num=1;
dfs(1,0,0,0,0);
for (i=1;i<=n;i++)
for (j=f[0][i];j;j=e[0][j].next)
if (b[i]!=b[e[0][j].to]) add(b[i],b[e[0][j].to],1);
dfs(1,0,1,1,0);
dfs(p,0,1,2,0);
printf("%d",(ans+1)>>1);
}