[codeforces 734E]Anton and Tree

【題目大意】

給一棵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);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章