[LCA模板]POJ1330 Nearest Common Ancestors

来源:互联网 发布:lte网络结构优化 编辑:程序博客网 时间:2024/05/17 23:47

题目链接 : 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