题目:
http://poj.org/problem?id=1330
题意:
给出一棵树,求其中两个点的最近公共祖先。
思路:
测试模版。
代码:
const int MAXN = 101001;
const int MAXM = 101001;
const int MAXQ = 101001;
struct Tree{
int head[MAXN];//前向星存图
int next[MAXM];
int to[MAXM];
int val[MAXM];//权值
int pos;
Tree()
{
clear();
}
void clear()
{
memset(head,-1,sizeof(head));
memset(val,0,sizeof(val));
pos = 0;
}
void add(int u,int v,int w)
{
val[pos] = w;
to[pos] = v;
next[pos] = head[u];
head[u] = pos++;
}
}tree;
bool v[MAXN];
int in[MAXN];//入度
int dist[MAXN];//与根节点距离
int father[MAXN];//并查集处理
int n,m,q;
vector<int>query[MAXQ],num[MAXQ];
int ans[MAXQ];
void Init()
{
memset(v,0,sizeof(v));
memset(in,0,sizeof(in));
memset(ans,0,sizeof(ans));
for(int i=0;i<MAXQ;i++)
{
query[i].clear();
num[i].clear();
}
tree.clear();
}
int Find(int x)
{
if(father[x] != x)
father[x] = Find(father[x]);
return father[x];
}
void getDist(int u)//计算节点到根距离
{
for(int i = tree.head[u];i!=-1;i=tree.next[i])
{
dist[tree.to[i]] = dist[u] + tree.val[i];
getDist(tree.to[i]);
}
}
void Tarjan(int u)
{
father[u] = u;//当访问到一个节点的时候,先将其自己形成一个集合
v[u] = true;//标记访问
for(int i = tree.head[u];i!=-1;i=tree.next[i])
{
Tarjan(tree.to[i]);//递归处理
father[tree.to[i]] = u;//处理结束后,将子节点集合加到父节点
}
for(int i = 0; i < query[u].size(); i++)//便利询问
{
if(v[query[u][i]])
{
ans[num[u][i]] =Find(query[u][i]);
}
}
}
int main()
{
int x,y,t,T;
#ifndef ONLINE_JUDGE
freopen("test.txt","r",stdin);
#endif
scanf("%d",&T);
while(T--)
{
Init();
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
tree.add(x,y,1);
in[y]++;
}
scanf("%d%d",&x,&y);
query[x].push_back(y);
query[y].push_back(x);
num[x].push_back(1);
num[y].push_back(1);
for(int i=1;i<=n;i++)
if(in[i] == 0)
{
dist[i]=0;
getDist(i);
Tarjan(i);
break;
}
printf("%d\n",ans[1]);
}
return 0;
}