pku Nearest Common Ancestors LCA 问题(rmq && tarjan)解决

http://poj.org/problem?id=1330

题意:给n个点,n-1条边,一棵树,求每个询问的LCA;

思路:

rmq求LCA。。。。http://dongxicheng.org/structure/lca-rmq/

View Code
#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

#include <stack>

#include <set>

#include <map>

#include <string>



#define CL(a,num) memset((a),(num),sizeof(a))

#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Min(a,b) (a) > (b)? (b):(a)

#define Max(a,b) (a) > (b)? (a):(b)



#define ll __int64

#define inf 0x7f7f7f7f

#define MOD 100000007

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define test puts("<------------------->")

#define maxn 100007

#define M 100007

#define N 10007

using namespace std;

//freopen("din.txt","r",stdin);



struct node{

    int v;

    int next;

}g[N];

int head[N],ct;



int E[2*N],R[N],D[2*N];

int dp[2*N][20],f[N],pow2[21];

bool vt[N];

int n,cnt;



void init(){

    for (int i = 0; i <= n; ++i){

        f[i] = -1;

        head[i] = -1;

    }

    ct = 0; cnt = 0;

    CL(vt,false);

}

void add(int u,int v){

    g[ct].v = v;

    g[ct].next = head[u];

    head[u] = ct++;

}

//E,R,D对应的值

void dfs(int u,int dep){

    vt[u] = true;

    E[cnt] = u;

    R[u] = cnt;

    D[cnt++] = dep;

    for (int i = head[u]; i != -1; i = g[i].next){

        int v = g[i].v;

        if (!vt[v]){

            dfs(v,dep + 1);

            E[cnt] = u;

            D[cnt++] = dep;

        }

    }

}

int MIN(int i,int j){

    if (D[i] < D[j]) return i;

    else return j;

}

void init_rmq(){



    int nn = 2*n - 1;

    int i,j;

    for (i = 0; i < nn; ++i)

        dp[i][0] = i;



    for (j = 1; pow2[j] <= nn; ++j){

        for (i = 0; (i + pow2[j] - 1) < nn; ++i)

        dp[i][j] = MIN(dp[i][j - 1],dp[i + pow2[j - 1]][j  - 1]);

    }

}

int rmq(int l,int r){

    int k = (int)(log(1.0*(r - l + 1))/log(2.0));

    return MIN(dp[l][k],dp[r - pow2[k] + 1][k]);

}

int main(){

    //freopen("din.txt","r",stdin);

    int T,i;

    int x,y;

    for (i = 0; i < 20; ++i) pow2[i] = 1<<i;

    scanf("%d",&T);

    while (T--){

        scanf("%d",&n);

        init();

        for (i = 1; i < n; ++i){

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

            add(x,y);

            f[y] = x;

        }

        //找出根节点

        for (i = 1; i <= n; ++i){

            if (f[i] == -1){

                break;

            }

        }

        cnt = 0;

        dfs(i,0);

        init_rmq();



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

        if (R[x] <= R[y]) printf("%d\n",E[rmq(R[x],R[y])]);

        else printf("%d\n",E[rmq(R[y],R[x])]);

    }

    return 0;

}

 

 tarjan离线处理:

View Code
#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

#include <stack>

#include <set>

#include <map>

#include <string>



#define CL(a,num) memset((a),(num),sizeof(a))

#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Min(a,b) (a) > (b)? (b):(a)

#define Max(a,b) (a) > (b)? (a):(b)



#define ll __int64

#define inf 0x7f7f7f7f

#define MOD 100000007

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define test puts("<------------------->")

#define maxn 100007

#define M 100007

#define N 10007

using namespace std;

//freopen("din.txt","r",stdin);



struct node{

    int v;

    int next;

}g[N];



int head[N],ct;

bool vt[N];

vector<int>ask[N];

int f[N],pa[N],pre[N];

int n;



int find(int x){

    if (x != f[x]) f[x] = find(f[x]);

    return f[x];

}

void Union(int x,int y){

    x = find(x);

    y = find(y);

    f[x] = y;

}

void add(int u,int v){

    g[ct].v = v;

    g[ct].next = head[u];

    head[u] = ct++;

}

void LCA(int u){

    int i;

    f[u] = u;//建立以当前节点为根的树

    for (i = head[u]; i != -1; i = g[i].next){

        int v = g[i].v;

        LCA(v);

        Union(u,v);//记住是u指向v

        pa[find(u)] = u;//记录该树的父节点

    }



    vt[u] = true;



    int sz = ask[u].size();

    for (i = 0; i < sz; ++i){

        if (vt[ask[u][i]]){//如果同时访问就可求出lca

            printf("%d\n",pa[find(ask[u][i])]);

        }

    }

}

int main(){

    //freopen("din.txt","r",stdin);

    int i;

    int T,x,y;

    scanf("%d",&T);

    while (T--){

        scanf("%d",&n);

        ct = 0; CL(head,-1); CL(pre,-1);

        for (i = 1; i < n; ++i){

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

            add(x,y);

            pre[y] = x;//记录父节点主要在于找根

        }



        for (i = 1; i <= n; ++i){

            f[i] = i;

            ask[i].clear();//离线处理

        }



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

        ask[x].push_back(y);

        ask[y].push_back(x);



        CL(vt,false);

        //找父节点

        for (i = 1; i <= n; ++i){

            if (pre[i] == -1) break;

        }

        LCA(i);

    }

    return 0;

}

 

 

你可能感兴趣的:(REST)