Cod sursa(job #1709511)

Utilizator team_nameUPB Banu Popa Visan team_name Data 28 mai 2016 12:41:08
Problema Revolta Scor 100
Compilator cpp Status done
Runda ONIS 2016 - Runda - 2 - ACM ICPC Romanian Programming Contest Marime 3.54 kb
#include <cstdio>
#include <vector>
#include <cassert>
#define MAXN 100005
#define MAXLOGN 18
#define INF 0x3f3f3f3f
using namespace std;

int nrt, n, dad[MAXN][MAXLOGN], lvl[MAXN], lvl2[MAXN], dad2[MAXN];
int d1[MAXN], d2[MAXN];
vector<int> G[MAXN];

void clearThings() {
    for(int i = 1; i <= n; ++i) {
        G[i].clear();
        lvl[i] = lvl2[i] = dad2[i] = 0;
        for(int j = 0; j < MAXLOGN; ++j)
            dad[i][j] = 0;
    }
}

void DFS(int u, int p) {
    int x = p;

    lvl[u] = lvl[p] + 1;
    for(int i = 0; i < MAXLOGN; ++i) {
        dad[u][i] = x;
        x = dad[x][i];
    }

    for(auto x: G[u])
        if(x != p)
            DFS(x, u);
}

int getDist(int x, int y) {
    int ans = 0;

    if(lvl[x] < lvl[y])
        swap(x, y);

    for(int i = MAXLOGN - 1; i >= 0; --i)
        if(lvl[x] - (1 << i) >= lvl[y]) {
            x = dad[x][i];
            ans += (1 << i);
        }

    if(x == y) return ans;

    for(int i = MAXLOGN - 1; i >= 0; --i)
        if(dad[x][i] != dad[y][i]) {
            x = dad[x][i];
            y = dad[y][i];

            ans += (1 << (i + 1));
        }

    return ans + 2;
}

void DFS2(int u, int p) {
    lvl2[u] = lvl2[p] + 1;
    dad2[u] = p;

    for(auto x: G[u])
        if(x != p)
            DFS2(x, u);
}

void getDiameter(vector<int> &diam) {
    int farthest = 1;
    for(int i = 2; i <= n; ++i)
        if(lvl[i] > lvl[farthest])
            farthest = i;

    DFS2(farthest, 0);

    int farthest2 = 1;
    for(int i = 2; i <= n; ++i)
        if(lvl2[i] > lvl2[farthest2])
            farthest2 = i;

    int x = farthest2;
    while(x) {
        diam.push_back(x);
        x = dad2[x];
    }
}

void addToDiam(int u, int p1, int p2, int &node1, int &node2, int &d) {
    int d1 = getDist(u, node1);
    int d2 = getDist(u, node2);

    if(d1 > d2) {
        if(d1 > d)
            node2 = u;
    }
    else if(d2 > d)
        node1 = u;

    d = max(d, max(d1, d2));

    for(auto x: G[u])
        if(x != p1 && x != p2)
            addToDiam(x, u, 0, node1, node2, d);
}

int diameterUnion(int d1, int d2) {
    int ans = max(d1, d2);
    ans = max(ans, (d1 + 1) / 2 + (d2 + 1) / 2);
    
    return ans;
}

int main() {
    freopen("revolta.in", "r", stdin);
    freopen("revolta.out", "w", stdout);

    scanf("%d", &nrt);

    while(nrt--) {
        scanf("%d", &n);
        clearThings();

        for(int i = 1; i < n; ++i) {
            int x, y;

            scanf("%d %d", &x, &y);

            G[x + 1].push_back(y + 1);
            G[y + 1].push_back(x + 1);
        }

        DFS(1, 0);

        vector<int> diam;
        getDiameter(diam);

        assert((int) diam.size() >= 2);
        
        int node1 = diam[0], node2 = diam[0];

        d1[(int) diam.size() - 1] = getDist(diam.front(), diam.back());

        d1[0] = 0;
        addToDiam(diam[0], diam[1], 0, node1, node2, d1[0]);

        for(int i = 1; i < (int) diam.size() - 1; ++i) {
            d1[i] = d1[i - 1];
            addToDiam(diam[i], diam[i - 1], diam[i + 1], node1, node2, d1[i]);
        }

        int last = (int) diam.size() - 1;        
        node1 = diam[last], node2 = diam[last];

        d2[last] = 0;
        d2[last - 1] = 0;
        addToDiam(diam[last], diam[last - 1], 0, node1, node2, d2[last - 1]);

        for(int i = last - 2; i >= 0; --i) {
            d2[i] = d2[i + 1];
            addToDiam(diam[i + 1], diam[i], diam[i + 2], node1, node2, d2[i]);
        }

        int ans = INF;
        for(int i = 0; i <= last; ++i)
            ans = min(ans, diameterUnion(d1[i], d2[i]));

        printf("%d\n", ans);
    }


    return 0;
}