pku 1330 Nearest Common Ancestors(四种方法实现)

//方法1,并查集+tarjan,离线的LCA算法,32MS

#include <stdio.h>
#include <string.h>
#include <vector>

 

using namespace std;

 

#define MAXN 10005

 

int N,father[MAXN],ance[MAXN];
vector<int> adjlist[MAXN];
vector<int> query[MAXN];
bool root[MAXN],color[MAXN];

 

int find_mfs(int x)
{
    int i,t;
    for(i=x;father[i]>0;i=father[i]) ;
    while(x!=i)
    {
        t=father[x];
        father[x]=i;
        x=t;
    }
    return i;
}
void merge_mfs(int x,int y)
{
    int fx,fy;
    fx=find_mfs(x);
    fy=find_mfs(y);
    if(fx==fy) return;
    if(father[fx]>father[fy]) //-3>-4
    {
        father[fy]+=father[fx];
        father[fx]=fy;
    }
    else
    {
        father[fx]+=father[fy];
        father[fy]=fx;
    }
}

void lca_tarjan(int u)
{
 //   father[u]=-1;
    ance[u]=u;
    for(size_t j=0;j<adjlist[u].size();j++)
    {
        int v=adjlist[u][j];
        lca_tarjan(v);
        merge_mfs(u,v);
        ance[find_mfs(u)]=u;
    }
    color[u]=true;
    for(size_t k=0;k<query[u].size();k++)
    {
        int w=query[u][k];
        if(color[w]) printf("%d\n",ance[ find_mfs(w) ]);
    }
}

int main()
{
    int test,M,i,j;
    scanf("%d",&test);
    while(test--)
    {
        scanf("%d",&N);
        for(i=1;i<=N;i++)
        {
            father[i]=-1;
            root[i]=true;
            color[i]=false;
            adjlist[i].clear();
            query[i].clear();
        }
        M=N-1;
        while(M--)
        {
            scanf("%d %d",&i,&j);
            root[j]=false;
            adjlist[i].push_back(j);
        }
        scanf("%d %d",&i,&j);
        query[i].push_back(j);
        query[j].push_back(i);
        for(i=1;i<=N;i++)
            if(root[i]) break;
        lca_tarjan(i);
    }
    return 0;
}

 

//****************************************************************

 

 

//方法2 很无语,就是逐层向上推找公共祖先 32MS

#include <iostream>
using namespace std;

 

#define VN 10005
#define EN 10005*4

 

struct
{
    int adv,next;
} edge[EN];


int index;
int adjlist[VN];
int depth[VN],dep,father[VN];

bool root[VN],visited[VN];

 

void insert(int i,int j)
{
    edge[index].adv=j;
    edge[index].next=adjlist[i];
    adjlist[i]=index++;
}

void dfs(int u,int dep)
{
    depth[u]=dep;
    visited[u]=true;
    int j,v;
    for(j=adjlist[u]; j!=-1; j=edge[j].next)
    {
        v=edge[j].adv;
        if(!visited[v])
        {
            father[v]=u;
            dfs(v,dep+1);
        }
    }
}
int LCA(int x,int y)
{
    while(depth[x]>depth[y])
        x=father[x];
    while(depth[y]>depth[x])
        y=father[y];
    while(x!=y)
    {
        x=father[x];
        y=father[y];
    }
    return x;
}

void init(int n)
{
    memset(adjlist,-1,n*4);
    memset(root,true,n);
    memset(depth,0,n);
    memset(visited,false,n);
}

int main()
{
    int test;
    scanf("%d",&test);
    while(test--)
    {
        int N,M,i,j;
        scanf("%d",&N);
        init(N+1);
        for(M=1; M<N; M++)
        {
            scanf("%d %d",&i,&j);
            insert(i,j);
            root[j]=false;
        }
        for(i=1; i<=N; i++)
            if(root[i]) break;
        dfs(i,1);
        scanf("%d %d",&i,&j);
        printf("%d\n",LCA(i,j));
    }
    return 0;
}

 

//*************************************************************************

 

//方法3 LCA->RMA,因为只询问一次,大材小用了,63MS

#include <stdio.h>
#include <math.h>
#include <vector>

 

using namespace std;

 

#define MAXN 10005
#define MAXLOG 16

 

vector<int> adjlist[MAXN];

int N;
int num,euler[MAXN*2],deep[MAXN*2],pos[MAXN],minst[MAXN*2][MAXLOG];
bool visited[MAXN],root[MAXN];

void dfs(int i,int depth)
{
    visited[i]=true;
    euler[num]=i;
    deep[num]=depth;
    pos[i]=num;
    for(size_t j=0; j < adjlist[i].size(); j++)
    {
        if(!visited[ adjlist[i][j] ])
        {
            visited[ adjlist[i][j] ]=true;
            ++num;
            dfs(adjlist[i][j],depth+1);
            ++num;
            euler[num]=i;
            deep[num]=depth;
        }
    }
}

void preprocess()
{
    int i,j,k,n=2*N-1,x,y;
    for(i=1;i<=n;i++) minst[i][0]=i;
    k=log(double(n))/log(2.0);
    for(j=1;j<=k;j++)
        for(i=1;i+(1<<j)-1<=n;i++)
        {
            x=deep[ minst[i][j-1] ];
            y=deep[ minst[i+(1<<(j-1))][j-1] ];
            if(x<y) minst[i][j]=minst[i][j-1];
            else minst[i][j]=minst[i+(1<<(j-1))][j-1];
        }
}
int rminq(int a,int b)
{
    int x,y,k=log(double(b-a+1))/log(2.0);
    x=deep[ minst[a][k] ];
    y=deep[ minst[b-(1<<k)+1][k] ];
    if(x<y) return minst[a][k];
    else return minst[b-(1<<k)+1][k];
}

inline void swap(int &a,int &b)
{
    int t=a;
    a=b;
    b=t;
}

int main()
{
    int T,M,i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(i=1;i<=N;i++)
        {
            adjlist[i].clear();
            visited[i]=false;
            root[i]=true;
        }
        M=N-1;
        while(M--)
        {
            scanf("%d %d",&i,&j);
            root[j]=false;
            adjlist[i].push_back(j);
        }
        num=1;
        for(i=1;i<=N;i++)
            if(root[i]) break;
        dfs(i,0);
        preprocess();
        int a,b;
        scanf("%d %d",&i,&j);
        a=pos[i];
        b=pos[j];
        if(a>b) swap(a,b);
        printf("%d\n",euler[ rminq(a,b) ]);
    }
    return 0;
}

 

//*************************************************************************

 

//方法4,LCA-》线段树,63MS

 

#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;

#define MAXN 10001

struct seg_tree
{
    int l,r,min;
};
seg_tree tree[MAXN*6];

vector<int> adjlist[MAXN];

bool root[MAXN],visited[MAXN];
int N,num,pos[MAXN],deep[MAXN*2],euler[MAXN*2];

void dfs(int i,int depth)
{
    visited[i]=true;
    pos[i]=num;
    deep[num]=depth;
    euler[num]=i;
    for(size_t j=0; j<adjlist[i].size(); j++)
    {
        int v=adjlist[i][j];
        if(!visited[v])
        {
            ++num;
            dfs(v,depth+1);
            ++num;
            deep[num]=depth;
            euler[num]=i;
        }
    }
}

inline int Min(int s1,int s2)
{
    return deep[s1]<deep[s2]?s1:s2;
}

void build(int a,int b,int idx)
{
    tree[idx].l=a;
    tree[idx].r=b;
    if(a==b)
    {
        tree[idx].min=a;
        return;
    }
    int mid=(a+b)/2;
    build(a,mid,idx*2);
    build(mid+1,b,idx*2+1);
    tree[idx].min=Min(tree[idx*2].min,tree[idx*2+1].min);
}
int query(int a,int b,int idx)
{
    if(a<=tree[idx].l && tree[idx].r<=b)
    {
        return tree[idx].min;
    }
    if(b<=tree[idx*2].r) return query(a,b,idx*2);
    else if(a>=tree[idx*2+1].l) return query(a,b,idx*2+1);
    else return Min( query(a,tree[idx*2].r,idx*2),query(tree[idx*2+1].l,b,idx*2+1) );
}

inline void swap(int &a,int &b)
{
    int t=a;
    a=b;
    b=t;
}

int main()
{
    int T,M,i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(i=1; i<=N; i++)
        {
            visited[i]=false;
            root[i]=true;
            adjlist[i].clear();
        }
        M=N-1;
        while(M--)
        {
            scanf("%d %d",&i,&j);
            root[j]=false;
            adjlist[i].push_back(j);
        }
        num=1;
        for(i=1; i<=N; i++)
            if(root[i]) break;
        dfs(i,0);
        build(1,2*N-1,1);
        int a,b,idx;
        scanf("%d %d",&i,&j);
        a=pos[i];
        b=pos[j];
        if(a>b) swap(a,b);
        idx=query(a,b,1);
        //       printf("a=%d b=%d idx=%d\n",a,b,idx);
        printf("%d\n",euler[ idx ]);
    }
    return 0;
}

 

 

posted @ 2010-08-19 17:33  菜到不得鸟  阅读(272)  评论(0)    收藏  举报