[LCA模板]POJ1330 Nearest Common Ancestors

题目链接 : http://poj.org/problem?id=1330

题目大意 :求一颗树的LCA

代码:

/*
    POJ 1330 给定一棵树 边的形式为a是b父亲 求LCA
    倍增
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define bit_cnt(x) __builtin_popcount((unsigned)x)
#define foru(i, a, b) for(int i=(a); i<=(b); i++)
#define ford(i, a, b) for(int i=(a); i>=(b); i--)
#define clr(a, b) memset(a, (b), sizeof(a))
typedef long long ll;
const double Pi = 4 * atan(1.0);

inline int readint() {
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    int ret = 0;
    while(isdigit(c)) ret = ret * 10 + c - '0', c = getchar();
    return ret;
}
/*************************************************************/
const int N = 10010;

int n, a, b, root, tot;
int adj[N], aim[2*N], next[2*N];
int anc[N][22], dep[N];

void add(int a, int b){
    tot ++;
    aim[tot] = b;
    next[tot] = adj[a];
    adj[a] = tot;
}

void dfs(int x, int pre){
    dep[x] = dep[pre]+1;
    int k = adj[x];
    while (k){
        int tx = aim[k];
        dfs(tx, x);
        k = next[k];
    }
}

int swim(int x, int H){
    for(int i = 0; H; i++){
        if (H&1) x = anc[x][i];
        H >>= 1;
    }
    return x;
}

int LCA(int x, int y){
    if (dep[x] < dep[y]) swap(x, y);
    x = swim(x, dep[x] - dep[y]);
    if (x == y) return x;
    ford(i, 20, 0)
        if (anc[x][i] != anc[y][i]) {
            x = anc[x][i];
            y = anc[y][i];
        }
    return anc[x][0];
}

int main(){
    freopen("POJ1330.txt", "r", stdin);
    int T; T = readint();
    while (T--){
        tot = 0; clr(adj, 0); clr(anc, 0);
        n = readint();
        foru(i, 1, n-1){
            a = readint();
            b = readint();
            add(a, b);
            anc[b][0] = a;
        }
        foru(i, 1, n) if (! anc[i][0]) {root = i; break;}
        anc[root][0] = root; dep[root] = 0; dfs(root, root);
        foru(j, 1, 20) foru(i, 1, n)
            anc[i][j] = anc[anc[i][j-1]][j-1];
        a = readint(); b = readint();
        printf("%d\n", LCA(a, b));
    }
    return 0;
}

Tips:

倍增求LCA:
    用acn[i][k]记录在点i处向上跳k层到达的点,预处理anc[i][0]=fa[i],利用anc[i][k] = anc[anc[i][k-1]] [k-1]转移
    函数swim(i,x)表示在i点向上跳H层到达的点,位运算按H的低位从高位依次跳实现
    函数LCA (a,b)表示求a,b的LCA,先另a,b跳到同一高度,若a == b则已找到LCA
    否则找到最小的H使得a == b(从高位到低位,若某一个k有anc[A][k] != anc[B][k],则A,B都跳H层) 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值