E. Anton and Tree 数组开大点

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

为什么直径 /  2是答案?因为可以在直径中间的那个点,一直变一直变。

原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6093446.html