[笔记]LCA 最近公共祖先---tarjan离线算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/78015866

一.定义:(出自百度百科)

对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。

二.离线算法(同上):

在开始时就需要知道问题的所有输入数据,而且在解决一个问题后就要立即输出结果。

即在算法开始前保存好所有的查询,结束后输出过程中求得的ans

三:基本思路
看到dalao的blog,本蒟蒻已无地自容 这是借口

四.伪代码(还是楼上的)

预处理: f a [ 1 ] = 1 ; v i s [ 1 ] = 1 fa[1]=1; vis[1]=1 ; //默认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;
}


猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/78015866