洛谷P3379 【模板】最近公共祖先(LCA)

倍增算法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read() {
    int x = 0, tmp = 1; char ch = getchar();
    while( ch < '0' || ch > '9' ) { if( ch == '-' ) tmp = -1; ch = getchar();    }
    while( ch >= '0' && ch <= '9' ) { x = x * 10 + ch - '0'; ch = getchar();    }
    return x * tmp;
}
inline void write( int k ) {
    if( k < 0 ) { putchar( '-' ); k = -k;    }
    if( k > 9 ) write( k / 10 );
    putchar( k % 10 + '0' );
}
struct Point {
    int to, next;
} edge[1100000];
int head[510000], idx = 0, dep[510000], f[510000][22];
bool vis[510000];
inline void ade( int u, int v ) {
    edge[++ idx].to = v;
    edge[idx].next = head[u];
    head[u] = idx;
}
void dfs( int x ) {
    vis[x] = 1;
    for( int i = 1 ; i <= 20 ; ++ i ) {
        if( dep[x] < ( 1 << i ) ) break;
        f[x][i] = f[f[x][i - 1]][i - 1];
    }
    for( int i = head[x] ; i != -1 ; i = edge[i].next ) {
        int now = edge[i].to;
        if( !vis[now] ) {
            dep[now] = dep[x] + 1;
            f[now][0] = x;
            dfs( now );
        }
    }
}
int lca( int u, int v ) {
    if( dep[u] > dep[v] ) swap( u, v );
    for( int i = 20 ; i >= 0 ; -- i ) if( dep[f[v][i]] >= dep[u] ) v = f[v][i];
    if( u == v ) return u;
    for( int i = 20 ; i >= 0 ; -- i ) if( f[v][i] != f[u][i] ) v = f[v][i], u = f[u][i];
    return f[u][0];
} 
int main() {
    memset( head, -1, sizeof( head ) );
    memset( f, 0, sizeof( f ) );
    memset( dep, 0, sizeof( dep ) );
    memset( vis, 0, sizeof( vis ) );
    int N = read(), M = read(), root = read();
    for( int i = 1 ; i < N ; ++ i ) {
        int x = read(), y = read();
        ade( x, y ); ade( y, x );
    } 
    dep[root] = 1;
    dfs( root );
    for( int i = 1 ; i <= M ; ++ i ) {
        int x = read(), y = read();
        write( lca( x, y ) );
        putchar( '\n' );
    }
    return 0;
}

tarjan算法

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
inline int read() {
    int x = 0, tmp = 1; char ch = getchar();
    while( ch < '0' || ch > '9' ) { if ( ch == '-' ) tmp = -1; ch = getchar();    }
    while( ch >= '0' && ch <= '9' ) { x = x * 10 + ch - '0'; ch = getchar();    }
    return x * tmp;
}
struct Point {
    int to, next;
} edge[1100000];
int head[510000], idx = 0;
bool vis[510000];
struct ansPoint {
    int to, next, num;
} ansedge[1100000];
int anshead[510000], ansidx = 0, ans[510000], group[510000];
inline void ade( int u, int v ) {
    edge[++ idx].to = v;
    edge[idx].next = head[u];
    head[u] = idx;
}
inline void ansade( int u, int v, int num ) {
    ansedge[++ ansidx].to = v;
    ansedge[ansidx].next = anshead[u];
    ansedge[ansidx].num = num;
    anshead[u] = ansidx;
}
int find( int x ) {
    int pre = x, y;
    while( x != group[x] ) x = group[x];
    while( pre != group[pre] ) {
        y = group[pre];
        group[pre] = x;
        pre = y;
    } 
    return x;
}
void dfs( int x ) {
    vis[x] = 1;
    group[x] = x;
    for( int i = head[x] ; i != -1; i = edge[i].next ) {
        int now = edge[i].to;
        if( !vis[now] ) {
            dfs( now );
            group[now] = x;
        } 
    } 
    for( int i = anshead[x] ; i != -1 ; i = ansedge[i].next ) {
        int now = ansedge[i].to, num = ansedge[i].num;
        if( vis[now] ) ans[num] = find( now );  
    }
}
int main() {
    memset( head, -1, sizeof( head ) );
    memset( anshead, -1, sizeof( anshead ) );
    int N = read(), M = read(), root = read();
    for( int i = 1 ; i < N ; ++ i ) {
        int x = read(), y = read();
        ade( x, y ); ade( y, x );
    }
    for( int i = 1 ; i <= M ; ++ i ) {
        int x = read(), y = read();
        ansade( x, y, i ); ansade( y, x, i );
    }
    dfs( root );
    for( int i = 1 ; i <= M ; ++ i ) printf( "%d\n", ans[i] );
}
posted @ 2017-03-10 20:18  ARZhu  阅读(127)  评论(0编辑  收藏  举报