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\n", (ans + 1)/2); return 0; }
skr