首页 > 代码库 > 在线查询树上最近公共祖先模板

在线查询树上最近公共祖先模板

在线查询树上最近公共祖先

标准题目

第一行有2个整数n和q:n代表树的结点数量,q代表询问的次数接下来n-1行每行两个整数u和v,表示结点u到结点v有一条边。
然后给出q组询问,每组询问由两个整数a和b构成,询问节点a和b的最近公共祖先。

样例数据

input
8 3
1 3
1 2
3 4
3 5
3 6
2 7
2 8
4 5
6 7
5 8

output:
3
1
1

代码

1. 邻接表建图

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <queue>
 6 using namespace std;
 7 const int lim=100000000;
 8 const int maxn=600010;
 9 struct point {
10     int to;
11     int nxt;
12 } edge[maxn*2];
13 int n,Q,tot=0;
14 int dep[maxn]= {0},f[20][maxn];
15 bool vis[maxn];
16 int head[maxn];
17 
18 void add(int u,int v) {
19     tot++;
20     edge[tot].to=v;
21     edge[tot].nxt=head[u];
22     head[u]=tot;
23 }
24 
25 
26 int Lca(int x,int y) { //lca
27     int temp,co=0,lca;
28     int tx=x,ty=y;
29     if(dep[tx]>dep[ty]) swap(tx,ty);
30     temp=dep[ty]-dep[tx];
31     while(temp) {
32         if(temp&1) ty=f[co][ty];
33         temp>>=1;
34         co++;
35     }
36     if(tx==ty) return tx;
37     else {
38         for(int j=19; j+1; j--) {
39             if((1<<j)>dep[tx]) continue;
40             if(f[j][tx]!=f[j][ty]) {
41                 tx=f[j][tx];
42                 ty=f[j][ty];
43             }
44         }
45         lca=f[0][tx];
46     }
47     return lca;
48 }
49 inline void bfs() {
50     queue<int> q;
51     vis[1]=1;
52     dep[1]=0;
53     q.push(1);
54     while(!q.empty()) { //宽搜处理dep和f[0][i] (父节点)
55         int tt=q.front();
56         q.pop();
57         for(int i=head[tt]; i; i=edge[i].nxt) {
58             int v=edge[i].to;
59             if(!vis[v]) {
60                 vis[v]=1;
61                 q.push(v);
62                 dep[v]=dep[tt]+1;
63                 f[0][v]=tt;
64             }
65         }
66     }
67 }
68 int main() {
69     memset(head,0,sizeof(head));
70     cin>>n>>Q;
71     for(int i=1; i<=n-1; i++) {
72         int a,b;
73         cin>>a>>b;
74         add(a,b);//双向建图
75         add(b,a);
76     }
77 
78     bfs();
79     for(int j=1; j<20; j++) //倍增
80         for(int i=1; i<=n; i++)
81             if(dep[i]>=(1<<j))
82                 f[j][i]=f[j-1][f[j-1][i]];
83     while(Q--) {
84         int a,b,lca;
85         cin>>a>>b;
86         lca=Lca(a,b);
87         cout<<lca<<endl;
88     }
89 
90     return 0;
91 }

 

2. Vector建图

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=600010;

int n,Q,tot=0;
int depth[maxn]= {0},f[20][maxn];
bool vis[maxn];
int head[maxn];
vector<int> edge[maxn];

void add(int u,int v) {
    edge[u].push_back(v);
}


int Lca(int x,int y) { //lca
    int temp,co=0,lca;
    int tx=x,ty=y;
    if(depth[tx]>depth[ty]) swap(tx,ty);
    temp=depth[ty]-depth[tx];
    while(temp) {
        if(temp&1) ty=f[co][ty];
        temp>>=1;
        co++;
    }
    if(tx==ty) return tx;
    else {
        for(int j=19; j+1; j--) {
            if((1<<j)>depth[tx]) continue;
            if(f[j][tx]!=f[j][ty]) {
                tx=f[j][tx];
                ty=f[j][ty];
            }
        }
        lca=f[0][tx];
    }
    return lca;
}
inline void bfs() {
    queue<int> q;
    vis[1]=1;
    depth[1]=0;
    q.push(1);
    while(!q.empty()) { //宽搜处理depth和f[0][i] 
        int now=q.front();
        q.pop();
        int len=edge[now].size();
        for(int i=0; i<len; i++) {
            int v=edge[now][i];
            if(!vis[v]) {
                vis[v]=1;
                q.push(v);
                depth[v]=depth[now]+1;
                f[0][v]=now;
            }
        }
    }
}
int main() {
    memset(head,0,sizeof(head));
    cin>>n>>Q;
    for(int i=1; i<=n-1; i++) {
        int a,b;
        cin>>a>>b;
        add(a,b);//双向建图
        add(b,a);
    }

    bfs();
    for(int j=1; j<20; j++) //倍增
        for(int i=1; i<=n; i++)
            if(depth[i]>=(1<<j))
                f[j][i]=f[j-1][f[j-1][i]];
    while(Q--) {
        int a,b,lca;
        cin>>a>>b;
        lca=Lca(a,b);
        cout<<lca<<endl;
    }

    return 0;
}

 

在线查询树上最近公共祖先模板