P3379 最近公共祖先(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

說明/提示

時空限制:1000ms,128M

數據規模:

對於30%的數據:N<=10,M<=10

對於70%的數據:N<=10000,M<=10000

對於100%的數據:N<=500000,M<=500000

樣例說明:

該樹結構如下:

第一次詢問:2、4的最近公共祖先,故爲4。

第二次詢問:3、2的最近公共祖先,故爲4。

第三次詢問:3、5的最近公共祖先,故爲1。

第四次詢問:1、2的最近公共祖先,故爲4。

第五次詢問:4、5的最近公共祖先,故爲4。

故輸出依次爲4、4、1、4、4。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define lt k<<1
#define rt k<<1|1
#define lowbit(x) x&(-x)
#define lson l,mid,lt
#define rson mid+1,r,rt
using namespace std;
typedef long long  ll;
typedef long double ld;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define mem(a, b) memset(a, b, sizeof(a))
#define int ll
const double pi = acos(-1.0);
const double eps = 1e-6;
const double C = 0.57721566490153286060651209;
const ll mod = 1ll << 32;
const int inf = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const uint INF = 0xffffffff;
const int maxn = 5e5 + 5;
struct node//vector 建邊
{
    int u, v, w, next;
    node () {};
    node(int u_, int v_, int next_)
    {
        u = u_;
        v = v_;
        next = next_;
    }
} edge[maxn * 2];
struct nodd
{
    int u, v, id, next;
    nodd() {};
    nodd(int u_, int v_, int id_, int next_)
    {
        u = u_;
        v = v_;
        id = id_;
        next = next_;
    }
} qu[maxn * 2];
int n, m, s;
int head[maxn], head1[maxn];
int cnt, cnt1;
int res[maxn][4];
int de[maxn], pre[maxn], fa[maxn];
bool vis[maxn];
void init()
{
    cnt = cnt1= 0;
    mem(vis, false);
    mem(head, -1);
    mem(head1, -1);
    mem(qu, 0);
    mem(edge, 0);
    for(int i=1; i<=n; i++)
    {
        fa[i] = i;
    }
}
void add_edge(int u, int v)
{
    edge[cnt] = (node)
    {
        u, v, head[u]
    };
    head[u] = cnt++;
}
void qu_edge(int u, int v, int id)
{
    qu[cnt1] = (nodd)
    {
        u, v, id, head1[u]
    };
    head1[u] = cnt1++;
}
int find_fa(int x)
{
    if(fa[x] == x) return x;
    else return fa[x] = find_fa(fa[x]);
}
void Tarjan(int x)
{
    vis[x] = true;
    for(int i=head[x]; ~i; i=edge[i].next)
    {
        int v = edge[i].v;
        if(!vis[v])
        {
            Tarjan(v);
            int r1 = find_fa(x);
            int r2 = find_fa(v);
            if(r1 != r2)
            {
                fa[r2] = r1;
            }
        }
    }
    for(int i=head1[x]; ~i; i=qu[i].next)
    {
        int v = qu[i].v;
        if(vis[v])
        {
            res[qu[i].id][2] = find_fa(v);
        }
    }
}
signed main()
{
    ios;
    cin >> n >> m >> s;
    init();
    for(int i=1; i<n; i++)
    {
        int u, v;
        cin >> u >> v;
        add_edge(u, v);
        add_edge(v, u);
    }
    for(int i=1; i<=m; i++)
    {
        int u, v;
        cin >> u >> v;
        qu_edge(u, v, i);
        qu_edge(v, u, i);
        res[i][0] = u;
        res[i][1] = v;
    }
    Tarjan(s);
    for(int i=1; i<=m; i++)
    {
        cout << res[i][2] << endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章