[最近公共祖先(LCA)]

首先这个题 很毒瘤 被数据卡了 很长时间

题目描述

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

输入输出格式

输入格式:

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

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

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

输出格式:

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

解析

结构体 来存  邻接表

d数组表示 这个点 的 深度

f 数组 表示 i 向上跳 2^k 步的点 

lg 数组 应该是个 常数优化

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,m,s,num;
 5 int d[500001],f[21][500001],lg[500001];
 6 int lin[1000001];
 7 struct qwq{
 8     int t,next;
 9 }zh[1000001];
10 void add(int x,int y)
11 {
12     num++;
13     zh[num].t=y;
14     zh[num].next=lin[x];
15     lin[x]=num; 
16 }
17 void dfs(int x,int y)
18 {
19     d[x]=d[y]+1;
20     f[0][x]=y;
21     for(int k=1;(1<<k)<=d[x];k++)
22         f[k][x]=f[k-1][f[k-1][x]];//f表示i向上跳2^k步的点 
23     for(int i=lin[x];i;i=zh[i].next)
24       if(zh[i].t!=y)
25         dfs(zh[i].t,x);
26 }
27 int LCA(int u,int v)
28 {
29     if(d[u]<d[v])//d表示这个点的深度 
30     swap(u,v);
31     while(d[u]>d[v])
32       u=f[lg[d[u]-d[v]]-1][u];
33     if(u==v)
34     return u;
35     for(int k=lg[d[u]]-1;k>=0;k--)
36     {
37         if(f[k][u]!=f[k][v])
38         u=f[k][u],v=f[k][v];
39     }
40     return f[0][u];
41 } 
42 int main()
43 {
44     scanf("%d%d%d",&n,&m,&s);
45     for(int i=1;i<n;i++)
46     {
47         int x,y;
48         scanf("%d%d",&x,&y);
49         add(x,y),add(y,x); 
50     }
51     dfs(s,0);
52     for(int i=1;i<=n;i++)
53       lg[i]=lg[i-1]+(1<<lg[i-1]==i);//常数优化? 
54     for(int i=1;i<=m;i++)
55     {
56         int x,y;
57         scanf("%d%d",&x,&y);
58         printf("%d\n",LCA(x,y));
59     }
60     return 0;
61 }

猜你喜欢

转载自www.cnblogs.com/-Wind-/p/10344010.html