您的位置:首页 > 其它

AC日记——【模板】最近公共祖先(LCA)洛谷 P3379

2017-02-04 08:38 381 查看

题目描述

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

输入输出格式

输入格式:

第一行包含三个正整数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


说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

该树结构如下:

#include <cstdio>
#include <algorithm>

#define maxn 500001

using namespace std;

struct EdgeType {
int to,next;
};
struct EdgeType edge[maxn<<1];

int f[maxn],head[maxn],num;
int n,m,s,if_z,dfn[maxn],cnt;

char Cget;

inline void read_int(int &now)
{
now=0,if_z=1,Cget=getchar();
while(Cget>'9'||Cget<'0')
{
if(Cget=='-') if_z=-1;
Cget=getchar();
}
while(Cget>='0'&&Cget<='9')
{
now=now*10+Cget-'0';
Cget=getchar();
}
now*=if_z;
}

inline void edge_add(int from,int to)
{
edge[++num].to=from,edge[num].next=head[to],head[to]=num;
edge[++num].to=to,edge[num].next=head[from],head[from]=num;
}

void search(int now,int fa)
{
dfn[now]=++cnt,f[now]=fa;
for(int i=head[now];i;i=edge[i].next)
{
if(edge[i].to==fa) continue;
search(edge[i].to,now);
}
}

inline int lca(int x,int y)
{
if(dfn[x]<dfn[y]) swap(x,y);
while(dfn[x]>dfn[y]) x=f[x];
while(dfn[y]>dfn[x]) y=f[y];
return y;
}

int main()
{
read_int(n),read_int(m),read_int(s);
int from,to;
for(int i=1;i<n;i++)
{
read_int(from),read_int(to);
edge_add(from,to);
}
search(s,0);
for(int i=1;i<=m;i++)
{
read_int(from),read_int(to);
printf("%d\n",lca(from,to));
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: