P3379 【模板】最近公共祖先(LCA)(倍增LCA)

题目链接:https://www.luogu.org/problem/P3379

题目大意:

  给一棵以s为根的无向树,回答m个询问,回答出a和b最近的公共祖先。

解题报告:

  倍增LCA的模板题,用一个数组 f [i] [j]表示i结点的第$2^{j}$个祖先。显然,一个点的祖先是f[i][0],对于当前点的第$2^{j}$个祖先的第$2^{j}$个祖先,等于当前点的第$2^{j+1}$个祖先,因为$2^{j}+2^{j}=2^{j+1}$。所以有递推式$f[i][j]=f[f[i][j-1]][j-1]$

  还有一个常数优化是打表预处理出log2(i)+1的值。

AC代码:

 

 1 #include<vector>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cmath>
 5 #include<queue>
 6 #include<stack>
 7 #include<cmath>
 8 #include<algorithm>
 9 #define numm ch-48
10 #define pd putchar(' ')
11 #define pn putchar('\n')
12 #define pb push_back
13 #define fi first
14 #define se second
15 #define fre1 freopen("1.txt","r",stdin)
16 #define fre2 freopen("2.txt","w",stdout)
17 using namespace std;
18 template <typename T>
19 void read(T &res) {
20     bool flag=false;char ch;
21     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
22     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
23     flag&&(res=-res);
24 }
25 template <typename T>
26 void write(T x) {
27     if(x<0) putchar('-'),x=-x;
28     if(x>9) write(x/10);
29     putchar(x%10+'0');
30 }
31 const int maxn=500010;
32 const int N=60;
33 const int inf=0x3f3f3f3f;
34 const int INF=0x7fffffff;
35 typedef long long ll;
36 struct node{
37     int v,net;
38 }e[maxn<<1];
39 int head[maxn],depth[maxn],lg[maxn],f[maxn][50],cnt;
40 void add(int u,int v) {
41     e[++cnt].v=v;
42     e[cnt].net=head[u];
43     head[u]=cnt;
44 }
45 void dfs(int fath,int now) {
46     depth[now]=depth[fath]+1;
47     f[now][0]=fath;
48     for(int i=1;(1<<i)<=depth[now];i++)
49         f[now][i]=f[f[now][i-1]][i-1];
50     for(int i=head[now];i!=-1;i=e[i].net)
51         if(e[i].v!=fath) dfs(now,e[i].v);
52 }
53 int lca(int x,int y) {
54     if(depth[x]<depth[y]) swap(x,y);
55     while(depth[x]>depth[y]) x=f[x][lg[depth[x]-depth[y]]-1];///x往父节点开始延伸
56     if(x==y) return x;  ///说明公共祖先为y,也就是当前的x
57     for(int i=lg[depth[x]]-1;~i;i--)
58         if(f[x][i]!=f[y][i])
59             x=f[x][i],y=f[y][i];
60     return f[x][0];
61 }
62 int main()
63 {
64     int n,m,s,a,b;
65     read(n),read(m),read(s);
66     fill(head+1,head+n+1,-1);
67     for(int i=1;i<=n-1;i++) {
68         read(a),read(b);
69         add(a,b),add(b,a);
70     }
71     dfs(s,s);
72     for(int i=1;i<=n;i++)   ///常数优化,预处理求出log2[i]+1的值
73         lg[i]=lg[i-1]+(1<<lg[i-1]==i);
74     for(int i=1;i<=m;i++) {
75         read(a),read(b);
76         write(lca(a,b));pn;
77     }
78     return 0;
79 }
代码在这里!

 

 

 

 

 

posted @ 2019-07-30 12:11  wuliking  阅读(217)  评论(0编辑  收藏  举报