http://codeforces.com/contest/734/problem/E
看了题解,缩点 + 树的直径。
然而一直wa14.
注意到,
缩点后重建图,在5的时候,5和6建了一条边,然后6的时候,又和5建一次边。这个时候就要大数组了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 2 * 200000 + 20; int first[maxn]; int first_sec[maxn]; int num, num_sec; struct node { int u, v, w; int tonext; }e[maxn * 2], e_sec[maxn * 2]; int col[maxn]; void add(int u, int v) { ++num; e[num].u = u; e[num].v = v; e[num].tonext = first[u]; first[u] = num; } void add_sec(int u, int v) { ++num_sec; e_sec[num_sec].u = u; e_sec[num_sec].v = v; e_sec[num_sec].tonext = first_sec[u]; first_sec[u] = num_sec; } bool vis[maxn]; int fa[maxn]; int find(int u) { if (u == fa[u]) return u; else return fa[u] = find(fa[u]); } void merge(int u, int v) { u = find(u); v = find(v); if (u != v) { fa[v] = u; } } void dfs(int cur) { for (int i = first[cur]; i; i = e[i].tonext) { int v = e[i].v; if (vis[v]) continue; vis[v] = true; if (col[cur] == col[v]) { merge(cur, v); } dfs(v); } } void dfs2(int cur) { printf("cur %d : %d ", cur, col[cur]); for (int i = first_sec[cur]; i; i = e_sec[i].tonext) { int v = e_sec[i].v; if (vis[v]) continue; vis[v] = true; dfs2(v); } } struct NODE { int cur, cnt; NODE(int aa, int bb) : cur(aa), cnt(bb) {} }; int bfs(int begin) { memset(vis, 0, sizeof vis); queue<struct NODE>que; while(!que.empty()) que.pop(); que.push(NODE(begin, 0)); vis[begin] = true; int mx = -inf; int to = begin; while (!que.empty()) { struct NODE t = que.front(); que.pop(); for (int i = first_sec[t.cur]; i; i = e_sec[i].tonext) { int v = e_sec[i].v; if (vis[v]) continue; que.push(NODE(v, t.cnt + 1)); vis[v] = true; if (mx < t.cnt + 1) { mx = t.cnt + 1; to = v; } } } if (to == begin) return 0; // cout << to << " " << mx << endl; que.push(NODE(to, 0)); memset(vis, 0, sizeof vis); vis[to] = true; mx = -inf; to = 0; while (!que.empty()) { struct NODE t = que.front(); que.pop(); for (int i = first_sec[t.cur]; i; i = e_sec[i].tonext) { int v = e_sec[i].v; if (vis[v]) continue; que.push(NODE(v, t.cnt + 1)); if (mx < t.cnt + 1) { mx = t.cnt + 1; to = v; } vis[v] = true; } } // cout << mx << " " << to << endl; return mx; } void work() { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) fa[i] = i; for (int i = 1; i <= n; ++i) scanf("%d", &col[i]); for (int i = 1; i <= n - 1; ++i) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); if (num > 200000 * 2) while(1); } vis[1] = true; dfs(1); // for (int i = 1; i <= n; ++i) { // printf("%d ", find(i)); // } for (int i = 1; i <= n; ++i) { for (int j = first[i]; j; j = e[j].tonext) { int v = e[j].v; if (find(i) == find(v)) continue; // printf("%d %d ", find(i), find(v)); // printf("fff"); add_sec(find(i), find(v)); add_sec(find(v), find(i)); } } // memset(vis, 0, sizeof vis); // vis[1] = 1; // dfs2(1); int ans = bfs(find(1)); cout << (ans + 1) / 2 << endl; } int main() { #ifdef local freopen("data.txt","r",stdin); #endif work(); return 0; }
为什么直径 / 2是答案?因为可以在直径中间的那个点,一直变一直变。