luogu 3379 最近公共祖先(树上倍增求LCA)

题目链接
思路

板子题,LCA有据我所知有暴力求法(过于暴力),树上倍增求法,tarjan(只能离线O(1)查询,不会)

vector 存图,需要氧气优化才能过,可能我写丑了。
链式前向星存图,开氧气优化效果倒不是很明显。

代码
#include 
using namespace std;

vector<int> e[500005];
//int tot = 0, first[500005];
//struct Node
//{
//    int v, next;
//}e[1000005];

//void add(int u, int v)
//{
//    e[tot].v = v;
//    e[tot].next = first[u];
//    first[u] = tot++;
//}

int deep[500005], f[500005][20], lg2[500005];

void dfs(int u, int fa)
{
    deep[u] = deep[fa]+1;
    f[u][0] = fa;
    for(int i = 1; (1<<i) < deep[u]; ++i) f[u][i] = f[f[u][i-1]][i-1];
    for(auto v : e[u]) if(v != fa) dfs(v,u);
//    for(int i = first[u]; ~i; i = e[i].next)
//    {
//        int v = e[i].v;
//        if(v != fa) dfs(v,u);
//    }
}

int lca(int x, int y)
{
    if(deep[x] > deep[y]) swap(x,y);
    while(deep[y] > deep[x]) y = f[y][lg2[deep[y]-deep[x]]];
    if(x == y) return x;
    for(int i = lg2[deep[x]]; ~i; --i) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}

int main()
{
    int n, m, root;
//    tot = 0;
//    memset(first,-1,sizeof(first));
    scanf("%d%d%d",&n,&m,&root);
    for(int i = 2; i <= n; ++i)
    {
        int u, v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
//        add(u,v);
//        add(v,u);
    }
    dfs(root,0);
    for(int i = 1; i <= n; ++i) lg2[i] = lg2[i-1]+(1<<lg2[i-1] == i); // 求 [log2(i)+1]
    for(int i = 1; i <= n; ++i) --lg2[i];
    while(m--)
    {
        int a, b;
        scanf("%d%d",&a,&b);
        printf("%d\n",lca(a,b));
    }
    return 0;
}

你可能感兴趣的:(#,倍增,LCA)