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;
}

 

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