CF 735E

题目:

一棵树上有黑白两种颜色,一次染色能对相同颜色的区域取反,求几次染色可使得整棵树为同一种颜色。

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;
}

猜你喜欢

转载自blog.csdn.net/mengwuyaaa/article/details/79968546