码迷,mamicode.com
首页 > 其他好文 > 详细

lca(洛谷P3379 最近公共祖先(LCA))

时间:2017-05-31 21:30:57      阅读:234      评论:0      收藏:0      [点我收藏+]

标签:return   size   using   返回   com   amp   传送门   lag   lca   

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先.

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果.

输入样例#1:
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
输出样例#1:
4
4
1
4
4
思路的话可以见我的转载博文:传送门
这是我的代码实现~
%:pragma GCC optmize(3)//o3优化,尽量不要开 
#include<bits/stdc++.h>
#define maxn 1100010
#define maxm 1100130
using namespace std;

int n,m,ss;
struct aaa{int to,next;}edge[maxn];

struct bbb{int same,to,next,num;bool flag;bbb(){flag=0;}}s[maxm];

int head[maxn],shead[maxm],pre[maxn],book[maxn],ans[maxm];

int cnt=0;

inline int read()//注意快读 
{
	char c=getchar();
	int num=0;
	while(!isdigit(c)) c=getchar();
	while(isdigit(c))
	{
		num=num*10+c-‘0‘;
		c=getchar();
	}
    return num;
} 

void add_edge(int u,int v)
{
	edge[++cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt;
	edge[++cnt].to=u;
	edge[cnt].next=head[v];
	head[v]=cnt;
}

int cntt=0;
void add_search(int u,int v,int w)
{
	s[++cntt].to=v;
	s[cntt].next=shead[u];
	s[cntt].num=w;
	shead[u]=cntt;
	
	s[++cntt].to=u;
	s[cntt].num=w;
	s[cntt].next=shead[v];
	shead[v]=cntt;
}

int find(int x)
{
	if(pre[x]==x) return x;
	else return pre[x]=find(pre[x]);
}

int merge(int x,int y)//注意谁和谁合并 
{
	int fx=find(x),fy=find(y);
	if(pre[fy]!=fx)
	{
		pre[fy]=fx;
		return 1;
	}
	return 0;
}

void tarjan(int point,int f)
{
	for(int i=head[point];i;i=edge[i].next)
		if(edge[i].to!=f&&!book[edge[i].to])//不能返回之前走过的点——父节点 
		{
			tarjan(edge[i].to,point);
			merge(point,edge[i].to);
			book[edge[i].to]=1;
		}
		
	for(int i=shead[point];i;i=s[i].next)
		if(book[s[i].to]&&!s[i].flag)
		{
			ans[s[i].num]=find(s[i].to);		
			s[i].flag=1;//走过的点标记 
			int tt=i;if(tt%2)tt++;else tt--;
			s[tt].flag=1;//因为是双向储存所以两边都要去掉 
		}
}

int main()
{
	scanf("%d%d%d",&n,&m,&ss);
	for(int i=1;i<n;i++)
	{
		int t1,t2;
		t1=read();t2=read();
		add_edge(t1,t2);
	}
	for(int i=1;i<=n;i++)
		pre[i]=i;
	for(int i=1;i<=m;i++)
	{
		int t1,t2;
		t1=read();t2=read();
		add_search(t1,t2,i);
	}
	tarjan(ss,0);//虚构一个父节点 
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}

  



lca(洛谷P3379 最近公共祖先(LCA))

标签:return   size   using   返回   com   amp   传送门   lag   lca   

原文地址:http://www.cnblogs.com/foreverpiano/p/6925836.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!