题目链接:http://poj.org/problem?id=1330
题目描述:给一棵有根树,求两点的最近公共祖先(LCA)
还是太弱了,都大三了,才正式学习如果求lca,,,,太弱了
好在这一次几乎把所有的求lca的方法都写了一遍,就当是入门吧。。。
方法一:暴力求解。预处理出 fa[]数组和dep[] 数组,然后就很简单了
方法二:tarjan。这个是一个离线的做法复杂度为O(n+Q)。需要用并查集来维护一下。主要是一个dfs,对于当前节点u,首先,dfs处理它的子孙;然后,查看所有的与当前节点u有关的查询,看另一个节点是否被标记,若被标记,则答案=find_fa(v),否则,不处理;最后,标记当前节点,并与其父节点合并;
方法三:倍增。预处理一个数组anc[i ][j ],表示i 节点向上走2^j次所到达的节点,如果越过根节点,答案就是根节点。剩下的看一下代码吧,想想就明白了!!另外这个做法可以增加节点,但是不能删除节点
方法四:rmq。先求出dfs序,转化成线性后,感觉舒爽多了,数组里面存的是该节点的深度,具体实现,自己想想吧,很巧妙。n个节点的树会转换成2n-1的数组。
方法五:我不太会,利用的是树链的思想。。。(弱渣伤不起。。。)
/*
暴力LCA
*///#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 10005;
const int M = N << 1;
int head[N], to[M], next[M],nedge;
void init()
{
memset(head, -1, sizeof(head));
nedge = 0;
}
void add(int a, int b)
{
to[nedge] = b, next[nedge] = head[a], head[a] = nedge++;
}
int fa[N], dep[N];
void get_fa_dep(int k, int dp)
{
dep[k] = dp;
for(int i = head[k]; i >= 0; i = next[i])
{
fa[to[i]] = k;
get_fa_dep(to[i], dp + 1);
}
}
bool mk[N];
int main()
{
#ifdef PKWV
freopen("in.in", "r", stdin);
#endif // PKWV
int T;
scanf("%d",&T);
while(T--)
{
init();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) mk[i]=false;
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
mk[b]=true;
add(a,b);
}
int root;
for(int i=1;i<=n;i++) if(!mk[i])
{
root=i;
break;
}
fa[root]=0;
get_fa_dep(root,0);
int a,b;
scanf("%d%d",&a,&b);
while(a!=b)
{
if(dep[a]<dep[b]) b=fa[b];
else if(dep[b]<dep[a]) a=fa[a];
else if(a!=b) a=fa[a],b=fa[b];
}
printf("%d\n",a);
}
return 0;
}
/*
tarjan LCA
*/
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 10005;
const int M = N;
int head[N],to[N],next[N],nedge;
int ind[N],fa[N];
void init()
{
nedge=0;
memset(head,-1,sizeof(head));
}
void add(int a,int b)
{
to[nedge]=b,next[nedge]=head[a],head[a]=nedge++;
}
bool mk[N];
int find_ind(int r)
{
if(ind[r]==r) return r;
return ind[r]=find_ind(ind[r]);
}
void unio(int i,int j)
{
ind[find_ind(j)]=find_ind(i);
}
int ans[10];
bool fl[N];
vector<int> v[N];
void dfs(int k)
{
for(int i=head[k];i>=0;i=next[i])
{
fa[to[i]]=k;
dfs(to[i]);
}
for(int i=0;i<v[k].size();i+=2)
{
int ed=v[k][i];
if(fl[ed])
{
ans[v[k][i+1]]=find_ind(ed);
}
}
fl[k]=true;
unio(fa[k],k);
}
int main()
{
#ifdef PKWV
freopen("in.in","r",stdin);
#endif // PKWV
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
memset(mk,false,sizeof(mk));
init();
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);mk[b]=true;
}
int root;
for(int i=1;i<=n;i++) if(!mk[i])
{
root=i;
break;
}
for(int i=1;i<=n;i++) v[i].clear();
int a,b;
scanf("%d%d",&a,&b);
v[a].PB(b),v[b].PB(a);
v[a].PB(0),v[b].PB(0);
memset(fl,false,sizeof(fl));
fa[root]=root;
for(int i=1;i<=n;i++) ind[i]=i;
dfs(root);
printf("%d\n",ans[0]);
}
return 0;
}
/*
倍增 LCA
*/
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 10005;
const int LG = 14;
const int M = N;
int head[N],to[M],next[M],nedge;
int up[N][LG],fa[N],root,dep[N];
bool mk[N];
void init()
{
memset(head,-1,sizeof(head));
memset(mk,false,sizeof(mk));
nedge=0;
}
void add(int a,int b)
{
to[nedge]=b,next[nedge]=head[a],head[a]=nedge++;
}
void dfs(int k,int dp)
{
up[k][0]=fa[k],dep[k]=dp;
int i=0;
while(up[k][i]!=root)
{
++i;
up[k][i]=up[up[k][i-1]][i-1];
}
while((++i)<LG) up[k][i]=root; /* very important !!! */
for(i=head[k];i>=0;i=next[i])
{
fa[to[i]]=k;
dfs(to[i],dp+1);
}
}
void swim(int &x,int h)
{
for(int i=0;h>0;i++)
{
if(h&1) x=up[x][i];
h>>=1;
}
}
int LCA(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
swim(a,dep[a]-dep[b]);
while(a!=b)
{
for(int i=0;;i++)
{
if(up[a][i]==up[b][i])
{
if(i==0) return up[a][i];
else {a=up[a][i-1],b=up[b][i-1];break;}
}
}
}
return a;
}
int main()
{
#ifdef PKWV
freopen("in.in","r",stdin);
#endif // PKWV
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
init();
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),mk[b]=true;
}
for(int i=1;i<=n;i++) if(!mk[i])
{
root=i;
break;
}
fa[root]=root;
dfs(root,0);
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",LCA(a,b));
}
return 0;
}
/*
RMQ LCA
*///#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;
const int N = 10005;
const int LG = 15;
const int M = N;
int head[N],to[M],next[M],nedge;
void init()
{
memset(head,-1,sizeof(head));
nedge=0;
}
void add(int a,int b)
{
to[nedge]=b,next[nedge]=head[a],head[a]=nedge++;
}
int first[N],a[N<<1],pt[N<<1],len;
void dfs(int k,int dp)
{
a[++len]=dp;first[k]=len;pt[len]=k;
for(int i=head[k];i>=0;i=next[i])
{
dfs(to[i],dp+1);
a[++len]=dp,pt[len]=k;
}
}
int rmq[N<<1][LG];
void getrmq()
{
int l=1;
for(int i=1;i<=len;i++) rmq[i][0]=i;
for(int i=1;l<=len;i++)
{
for(int j=1;j<=len;j++)
{
if(j+l<=len&&a[rmq[j][i-1]]>a[rmq[j+l][i-1]])
rmq[j][i]=rmq[j+l][i-1];
else rmq[j][i]=rmq[j][i-1];
}
l<<=1;
}
}
int RMQ(int u,int v)
{
int k=log((long double)(v-u+1))/log(2.0);
int l=(int)pow((long double)2,k);
if(a[rmq[u][k]]<a[rmq[v-l+1][k]]) return rmq[u][k];
else return rmq[v-l+1][k];
}
bool mk[N];
int main()
{
#ifdef PKWV
freopen("in.in","r",stdin);
#endif // PKWV
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
init();
memset(mk,false,sizeof(mk));
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);mk[v]=true;
}
int root;
for(int i=1;i<=n;i++) if(!mk[i])
{
root=i;
break;
}
len=0;
dfs(root,0);
getrmq();
int u,v;
scanf("%d%d",&u,&v);
u=first[u],v=first[v];
if(u>v) swap(u,v);
printf("%d\n",pt[RMQ(u,v)]);
}
return 0;
}