CF734E Anton and Tree(思维+dp)
题目告诉我们连通块是一次染色的,因此我们将所有连通块缩点,这样树就变成了黑白相间且与原答案一样的树
对于这种树,我们采用贪心的策略,从树直径不断往外染色,那么染完直径就是答案。
这是因为我们直径上要黑白相间的染,这样对于其他的分支,也会不断地改变,当我们染完直径,其他不可能有比他更长的没被染色
并且直径是必须染色的,所以答案就是染完直径
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+10; const int inf=0x3f3f3f3f; int h[N],e[N],ne[N],idx; vector<int> g[N]; int col[N]; int f[N][2]; int a[N]; int ans; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs(int u,int fa){ if(col[u]==col[fa]) a[u]=a[fa]; else{ g[a[u]].push_back(a[fa]); g[a[fa]].push_back(a[u]); } int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u); } } int dfs1(int u,int fa){ int i; f[u][0]=f[u][1]=0; for(i=0;i<(int)g[u].size();i++){ int j=g[u][i]; if(j==fa) continue; int dis=dfs1(j,u)+1; if(dis>=f[u][0]){ f[u][1]=f[u][0]; f[u][0]=dis; } else if(dis>f[u][1]){ f[u][1]=dis; } } ans=max(ans,f[u][1]+f[u][0]); return f[u][0]; } int main(){ ios::sync_with_stdio(false); memset(h,-1,sizeof h); int i; int n; cin>>n; for(i=1;i<=n;i++){ cin>>col[i]; a[i]=i; } for(i=1;i<n;i++){ int a,b; cin>>a>>b; add(a,b); add(b,a); } col[0]=2; dfs(1,1); dfs1(1,0); cout<<(ans+1)/2<<endl; }
没有人不辛苦,只有人不喊疼