版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/78015866
一.定义:(出自百度百科)
对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。
二.离线算法(同上):
在开始时就需要知道问题的所有输入数据,而且在解决一个问题后就要立即输出结果。
即在算法开始前保存好所有的查询,结束后输出过程中求得的ans
三:基本思路:
看到dalao的blog,本蒟蒻已无地自容 这是借口
四.伪代码(还是楼上的)
预处理: ; //默认1为根
Tarjan(u)//marge和find为并查集合并函数和查找函数
{
for each(u,v) //访问所有u子节点v
if(!vis[v])
{
标记v被访问过:vis[v]=1;
初始化fa[v]=v;
Tarjan(v); //继续往下遍历
marge(u,v); //合并v到u上
}
for each(u,e) //访问所有和u有询问关系的e
{
如果e被访问过;
u,e的最近公共祖先为find(e);
}
}
五.查询的储存
类前向星
struct Query
{
int to; //v
int next; //下一个
int index; //查询编号
};
int ans[20005]; //记录ans
int qcnt; //结构体大小
int qhead[10005]; //u的索引
Query query[40005];
inline void addQuery(int x,int y,int z) //加入
{
++qcnt;
query[qcnt].to=y;
query[qcnt].next=qhead[x];
query[qcnt].index=z;
qhead[x]=qcnt;
}
六.模板
#include <cstdio>
#include <cstdlib>
#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
#define close fclose(stdin); fclose(stdout);
using namespace std;
struct Edge
{
int to;
int next;
};
int ecnt;
int head[500005];
Edge edge[1000005];
inline void addEdge(int x,int y)
{
++ecnt;
edge[ecnt].to=y;
edge[ecnt].next=head[x];
head[x]=ecnt;
}
struct Query
{
int to;
int next;
int index;
};
int ans[500005];
int qcnt;
int qhead[500005];
Query query[1000005];
inline void addQuery(int x,int y,int z)
{
++qcnt;
query[qcnt].to=y;
query[qcnt].next=qhead[x];
query[qcnt].index=z;
qhead[x]=qcnt;
}
int vis[500005];
int fa[500005];
inline int read()
{
int k=1;
int sum=0;
char c=getchar();
for(;'0'>c || c>'9' ;c=getchar())
if(c=='-') k=-1;
for(;'0'<=c && c<='9';c=getchar())
sum=sum*10+c-'0';
return sum*k;
}
inline void write(int x)
{
if(x<0) { putchar('-'); x*=-1; }
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline int find(int x)
{
return fa[x]=(fa[x]==x?x:find(fa[x]));
}
inline void join(int x,int y)
{
int x1=find(x),y1=find(y);
if(x1==y1) return ;
fa[y1]=x1;
}
inline void LCA(int p)
{
for(int i=head[p];i;i=edge[i].next)
if(!vis[edge[i].to])
{
int y=edge[i].to;
vis[y]=1;
fa[y]=y;
LCA(y);
join(p,y);
}
for(int i=qhead[p];i;i=query[i].next)
if(!ans[query[i].index] && vis[query[i].to])
{
int y=query[i].to,z=query[i].index;
ans[z]=find(y);
}
}
int main()
{
open("3379");
int n=read(),m=read();
int x1=read();
for(int i=1;i<n;++i)
{
int x=read(),y=read();
addEdge(x,y);
addEdge(y,x);
}
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
addQuery(x,y,i);
addQuery(y,x,i);
}
fa[x1]=x1;
vis[x1]=1;
LCA(x1);
for(int i=1;i<=m;++i)
{
write(ans[i]);
putchar('\n');
}
close;
return 0;
}