0w1

ABC 14 D - 閉路 ( Doubling LCA )

D: 閉路 - AtCoder Beginner Contest 014 | AtCoder
A small practice for doubling LCA.

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXQ = 1e5 + 5;
const int LGN = 20; // 2 ^ 19 > 1e5

int n;
vector<int> G[ MAXN ]; // connects to what
int q;
int a[ MAXN ], b[ MAXN ];

int dpt[ MAXN ]; // depth
int par[ LGN ][ MAXN ]; // par[ i ][ j ]: 2 ^ i ancestor of node j 

void dfs(int u, int fa, int d){
    dpt[ u ] = d;
    par[ 0 ][ u ] = fa;
    for(int v: G[ u ]){
        if( v == fa ) continue;
        dfs( v, u, d + 1 );
    }
}

void preDouble(){ // if par[ i ][ j ] = 0, no such ancestor exists
    for(int i = 1; i < LGN; ++i)
        for(int j = 1; j <= n; ++j){
            int ha = par[ i - 1 ][ j ];
            par[ i ][ j ] = par[ i - 1 ][ ha ];
        }
}

int lca(int u, int v){
    if( dpt[ u ] < dpt[ v ] ) swap<int>( u, v );
    int diff = dpt[ u ] - dpt[ v ];
    for(int k = 0; k < LGN; ++k){
        if( diff & 1 ) u = par[ k ][ u ];
        diff >>= 1;
    }
    if( u == v ) return u;
    for(int k = LGN - 1; k >= 0; --k)
        if( par[ k ][ u ] != par[ k ][ v ] ){
            u = par[ k ][ u ];
            v = par[ k ][ v ];
        }
    assert( par[ 0 ][ u ] == par[ 0 ][ v ] );
    return par[ 0 ][ u ];
}

int dis(int u, int v){ // make sure u or v is the other's root
    return abs( dpt[ u ] - dpt[ v ] );
}

void solve(){
    dfs( 1, 0, 0 ); // let 1 be the root
    preDouble();
    for(int i = 0; i < q; ++i){
        int u = a[ i ], v = b[ i ];
        int ans = dis( u, lca( u, v ) ) + dis( v, lca( u, v ) ) + 1;
        printf("%d\n", ans);
    }
}

int main(){
    scanf("%d", &n);
    for(int i = 0; i < n - 1; ++i){
        int x, y; scanf("%d%d", &x, &y);
        G[ x ].push_back( y );
        G[ y ].push_back( x );
    }
    scanf("%d", &q);
    for(int i = 0; i < q; ++i)
        scanf("%d%d", &a[ i ], &b[ i ]);
    solve();
    return 0;
}