题目:
一棵树上有黑白两种颜色,一次染色能对相同颜色的区域取反,求几次染色可使得整棵树为同一种颜色。
PS: 还是刷不动F,心累。
题解:
缩点后求树的直径/2 。
不严谨证明:
把一棵树立起来,不断地对树根染色,这样就会发现只需要考虑最长的树链。同理,如果对树链上某一点着色,一定次数的操作后会等价于对树根染色,贪心地选取,这个点应该是最长树链的中点。
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int n;
int maxlen=0;
int duan=0;
int arr[201000];
int in[201000];
bool vis[201000];
bool vistuan[201000];
vector<int> vec[201000];
vector<int> tuan[201000];
void dfs(int bit,int x,int color){
if(vis[x]) return ;
if(arr[x]!=color) return ;
in[x]=bit;
vis[x]=true;
for(int i=0;i<vec[x].size();i++){
dfs(bit,vec[x][i],color);
}
}
void findlen(int x,int len){
if(vistuan[x]) return ;
vistuan[x]=true;
if(len>maxlen){
duan=x;
maxlen=len;
}
for(int i=0;i<tuan[x].size();i++){
findlen(tuan[x][i],len+1);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>arr[i];
for(int i=0;i<n-1;i++){
int a,b;
cin>>a>>b;
vec[a].push_back(b);
vec[b].push_back(a);
}
int bit=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs(bit,i,arr[i]);
bit++;
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<vec[i].size();j++){
int to=vec[i][j];
if(in[i]!=in[to]){
tuan[in[i]].push_back(in[to]);
}
}
}
findlen(1,1);
maxlen=0;
memset(vistuan,0,sizeof(vistuan));
findlen(duan,1);
cout<<maxlen/2<<endl;
}