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;
}
浙公网安备 33010602011771号