題目鏈接: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;
}