Codeforces Round #379 (Div. 2) E. Anton and Tree 缩点 树的直径

传送门

题意:

这道题说的是在一颗有两种颜色的树上,每操作一个节点,可以改变这个节点颜色和相邻同色节点的颜色。问最少操作次数,使得树上颜色相同。

思路:

先缩点,把相同的颜色的相邻节点缩在一起。再求出树的最长直径S(边的个数),答案就是(S + 1)/ 2;

因为对于一条链,我们可以从中间向两边交换改变。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

const int MAXN = 2e5+9;
vector<int>mp[MAXN],newmap[MAXN];
int n,a[MAXN],col[MAXN],h[MAXN],fa[MAXN];
bool vis[MAXN];
int ans = 0;
void dfs(int u, int c){
    vis[u] = true;
    col[u] = c;
    for(int i=0; i < mp[u].size(); i++){
        int v = mp[u][i];
        if(a[v]!=a[u])continue;
        if(vis[v])continue;
        dfs(v,c);
    }
}
void dfs2(int u, int o){

    int mx = 0,mxx = 0;
    for(int i=0; i<newmap[u].size(); i++){
        int v = newmap[u][i];
        if(v==o)continue;
        dfs2(v,u);
        mx = max(mx,h[v] + 1);
        if(mx > mxx)swap(mx,mxx);
    }
    h[u] =  mxx;
    ans = max (ans, mxx + mx);
}
int main(){
    scanf("%d", &n);
    for(int i=1; i<=n; i++){
        scanf("%d", &a[i]);
    }
    for(int i=1; i<n; i++){
        int u,v;
        scanf("%d%d", &u, &v);
        mp[u].pb(v);
        mp[v].pb(u);
    }
    int cnt = 1;
    for(int i=1; i<=n; i++){
        if(!vis[i]){
            dfs(i , cnt++);
        }
    }
    for(int i=1; i<=n; i++){
        for(int k = 0; k < mp[i].size(); k++){
            if(col[i] != col[mp[i][k]]){
                newmap[col[i]].pb(col[mp[i][k]]);
            }
        }
    }
    dfs2(1, -1);
    printf("%d
", (ans + 1)/2);
    return 0;
}
CF734E
原文地址:https://www.cnblogs.com/ckxkexing/p/9295226.html