LCA--ノート

トピック- 最近の共通の祖先

Tagjan

すべてのお問い合わせは、最大保存されます

その後、再び、すべてのLCAを来DFS

非常に素晴らしいです

本質的に以下に基づいて
13及び14は7であるLCA

場合7の$ \色{赤}にDFS \テキスト{} $ OFFアナログ3--7

そして、左のサブツリーを検索

vis[13] = 1

その後、右のサブツリーを検索する場合

搜到14 并从此继续搜索 回溯后检查发现vis[13] = 1 update答案 

それは言うことができます

同じサブツリー内の2つのノードではない以下の最近の公共のLCA


#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
 
inline void Read(int &x)
{
    x = 0;
    char a = getchar();
    bool f = 0;
    while(a < '0'||a > '9') {if(a == '-') f = 1;a = getchar();}
    while(a >= '0'&&a <= '9') {x = x * 10 + a - '0';a = getchar();}
    if(f) x *= -1;
}
const int MAXN = 500001;
vector<int> G[MAXN];
vector<pair<int,int> > Ask[500001];
//存询问
int f[MAXN],ans[MAXN];
/*
f用并查集来维护加删边
ans用于统一输出
*/
bool vis[MAXN],Get[MAXN];
inline int Find_set(int x)
{
    if(f[x] == x) return x;
    return f[x] = Find_set(f[x]);
}
inline void Union(int u,int v)
{
    int A1 = Find_set(u),A2 = Find_set(v);
    if(A1 != A2) f[A1] = A2;
}
//并查集的标准操作
inline void Tagjan(int x)
{
    int i;
    for(i = 0;i < G[x].size();i++)
    {
        if(!vis[G[x][i]])
        {
            vis[G[x][i]] = 1;
            Tagjan(G[x][i]);
            Union(G[x][i],x);
            /*先Tagjan下去,再连边
            因为要模拟断边
            */
        }
    }
    //遍历整个子树
    for(i = 0;i < Ask[x].size();i++)
    {
        int v = Ask[x][i].first,Index = Ask[x][i].second;
        if(vis[v]) ans[Index] = Find_set(v);
        /*因为u已经遍历到了
        v在其他子树的话,上层断边,确保ans
        v就在此子树的话,u已断边,v必搜到u
        */
    }
}
int main()
{
    int i,n,m,s;
    Read(n),Read(m),Read(s);
    for(i = 1;i < n;i++)
    {
        f[i] = i;
        int u,v;
        Read(u),Read(v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(i = 1;i <= m;i++)
    {
        int u,v;
        Read(u),Read(v);
        Ask[u].push_back(make_pair(v,i));
        Ask[v].push_back(make_pair(u,i));
        //两边都要push进去,因为不清楚谁更浅
    }
    vis[s] = 1;
    //初始一定要清!!!!!
    Tagjan(s);
    for(i = 1;i <= m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

別の方法

セグメントツリーのメンテナンスだけでなく、以下の原則に基づいて、

ツリーとして地図上のDFS系列4,3,7,5と呼ばれるものがあります(便利なように

DFSの序文3437353

2つの値の間の共通の祖先のいずれかの2つのノードが配列に対応すること

そのような7として及び4 - > 3

しかし、これは、セグメントツリーを維持するのに十分ではありません

新しいアレイ上

dep[i] 记录i的深度

それはなった静的範囲クエリの問題

もちろん、他のデータ構造も使用することができます

後ここ羅バレーポイント、それ

しかし、酸素が存在しません しかし、ポイント間の差がある2ミリ秒 TLEはああ

#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
 
inline void Read(int &x)
{
    x = 0;
    char a = getchar();
    bool f = 0;
    while(a < '0'||a > '9') {if(a == '-') f = 1;a = getchar();}
    while(a >= '0'&&a <= '9') {x = x * 10 + a - '0';a = getchar();}
    if(f) x *= -1;
}
const int MAXN = 500001;
int tot,seq[MAXN << 1],Index[MAXN],dep[MAXN + 2];
//seq[]记录dfs序,Index记录结点在dfs序的位子,dep深度(说过了
vector<int> G[MAXN];
bool vis[MAXN];
inline void dfs(int x)
{
    seq[++tot] = x;
    Index[x] = tot;
    for(int i = 0;i < G[x].size();i++)
    {
        if(!vis[G[x][i]])
        {
            vis[G[x][i]] = 1;
            dep[G[x][i]] = dep[x] + 1;
            dfs(G[x][i]);
            seq[++tot] = x;
        }
    }
}
template<typename T>
inline T Min(T a,T b) {if(a < b) return a;return b;}
template<typename T>
inline void exchange(T &a,T &b) {T c = a;a = b;b = c;}
int tree[MAXN << 3],Left,Right;
//tree[MAXN << 3]一定是3,因为是针对seq[MAXN << 1]的
inline void tree_build(int l,int r,int k)
{
    if(l == r)
    {
        tree[k] = seq[l];
        return;
    }
    int mid = l + r >> 1;
    tree_build(l,mid,k << 1);
    tree_build(mid + 1,r,k << 1 ^ 1);
    if(dep[tree[k << 1]] < dep[tree[k << 1 ^ 1]])
        tree[k] = tree[k << 1];
    else tree[k] = tree[k << 1 ^ 1];
    //是比较深度,不是比较编号大小
}
inline int query(int l,int r,int k)
{
    if(Left <= l&&r <= Right)
        return tree[k];
    int mid = l + r >> 1,A1,A2;
    A1 = A2 = MAXN + 1;
    //main中写了dep[MAXN + 1] = 极大值
    if(Left <= mid) 
        A1 = query(l,mid,k << 1);
    if(mid < Right)
        A2 = query(mid + 1,r,k << 1 ^ 1);
    if(dep[A1] < dep[A2])
        return A1;
    return A2;
}
int main()
{
    dep[MAXN + 1] = 5000011;
    int n,m,i,S;
    Read(n),Read(m);
    Read(S);
    //它给定根
    for(i = 1;i <= n - 1;i++)
    {
        int u,v,w;
        Read(u),Read(v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    vis[S] = 1;
    dfs(S);
    tree_build(1,tot,1);
    while(m--)
    {
        int u,v;
        Read(u),Read(v);
        Left = Index[u],Right = Index[v];
        if(Left > Right) exchange(Left,Right);
        //可能顺序不对
        int LCA = query(1,tot,1);
        printf("%d\n",LCA);
    }
    return 0;
}

延ばします

あなたは、uからvへの最短距離を見つけた場合

なることができます

power[u] + power[v] - 2 * power[LCA(u,v)]

乗算

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
inline void Read(int &x)
{
    x = 0;
    char a = getchar();
    bool f = 0;
    while(a < '0'||a > '9') {if(a == '-') f = 1;a = getchar();}
    while(a >= '0'&&a <= '9') {x = x * 10 + a - '0';a = getchar();}
    if(f) x *= -1;
}
const int MAXN = 50001,MAXK = 50;
int dep[MAXN],f[MAXN][MAXK];
long long power[MAXN],all;
bool vis[MAXN];
vector<int> G[MAXN],Road[MAXN];
inline void dfs(int u)
{
    for(int i = 0;i < G[u].size();i++)
    {
        if(!vis[G[u][i]])
        {
            vis[G[u][i]] = 1;
            dep[G[u][i]] = dep[u] + 1;
            f[G[u][i]][0] = u;
            power[G[u][i]] = power[u] + Road[u][i];
            dfs(G[u][i]);
        }
    }
}
inline void adjust(int &u,int val)
{
    for(int i = MAXK - 1;i >= 0;i--)
        if(dep[f[u][i]] >= val)
            u = f[u][i];
}
inline int lca(int u,int v)
{
    if(dep[u] > dep[v]) adjust(u,dep[v]);
    else if(dep[u] < dep[v]) adjust(v,dep[u]);
    if(u == v) return u;
    for(int i = MAXK - 1;i >= 0;i--)
        if(f[u][i] != f[v][i])
            u = f[u][i],v = f[v][i];
    return f[u][0];
}
inline void count(int u,int v)
{
    int w = lca(u,v);
    all += power[u] + power[v] - power[w] * 2;
}
int main()
{
    int n;
    bool F = 0;
    while(~scanf("%d",&n))
    {
        if(F) putchar('\n');
        F = 1;
        int i,m;
        memset(vis,0,sizeof(vis));
        memset(dep,0,sizeof(dep));
        memset(f,0,sizeof(f));
        memset(power,0,sizeof(power));
        for(i = 1;i <= n;i++) G[i].clear(),Road[i].clear();
        for(i = 1;i < n;i++)
        {
            int u,v,w;
            Read(u),Read(v),Read(w);
            u++,v++;
            G[u].push_back(v);
            G[v].push_back(u);
            Road[u].push_back(w);
            Road[v].push_back(w);
        }
        vis[1] = 1;
        dfs(1);
        f[1][0] = 1;
        for(i = 1;i < MAXK;i++)
            for(int j = 1;j <= n;j++)
                f[j][i] = f[f[j][i - 1]][i - 1];
        Read(m);
        while(m--)
        {
            int a,b,c;
            Read(a),Read(b),Read(c);
            a++,b++,c++;
            all = 0;
            count(a,b),count(b,c),count(a,c);
            printf("%lld\n",all / 2);
        }
        
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/resftlmuttmotw/p/11323277.html