逆天周赛题,考虑先缩连通块,然后选一条直径扩张,每次会把周围的不同色点“吸”进来,答案是直径一半上取整。
充分必要性都容易证明吧。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
#include <vector>
#include <queue>
#include <cassert>
using namespace std;
#define PII pair<int,int>
#define x first
#define y second
#define For(i, l, r) for(int i = l; i <= r; i ++)
#define Rep(i, l, r) for(int i = l; i >= r; i --)
bool START;
void in(int &x)
{
char c = getchar(); int op = 1;
while(c > '9' || c < '0') op *= (c == '-' ? -1 : 1), c = getchar();
for(x = 0; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0'; x *= op;
}
const int N = 2e5 + 50;
int n, m, f[N], a[N], z[3], fa[N];
vector<int> G[N];
int ans;
void Dfs(int u, int pa)
{
for(int v : G[u]) if(v != pa)
{
Dfs(v, u);
ans = max(ans, f[u] + f[v] + 1);
f[u] = max(f[u], f[v] + 1);
}
}
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
PII p[N];
bool ENDPOS = 0;
int main()
{
in(n);
For(i, 1, n) in(a[i]);
For(i, 1, n) fa[i] = i;
For(i, 1, n - 1)
{
int u, v; in(u); in(v); p[i] = {u, v};
if(a[u] == a[v]) fa[find(u)] = find(v);
}
For(i, 1, n - 1)
{
int u = p[i].x, v = p[i].y;
if(find(u) == find(v)) continue;
u = find(u); v = find(v);
G[u].push_back(v); G[v].push_back(u);
}
int rt = find(1);
Dfs(rt, 0);
printf("%d\n", (ans + 1) / 2);
return 0;
}