zoukankan      html  css  js  c++  java
  • 树上倍增求LCA(RMQ)

    板子(反正我只是个垃圾)

    //树上倍增求LCA(RMQ),其实就是个简单的二进制拆分问题
    //正确性很容易证明,不证了
    //思想:eg: 求x节点和y节点的Lca,比较 x 与 y 节点的深度,将树中深的节点跳到
    //与浅的节点相同深度(由大到小循环),如果刚好为深度浅的节点,那么就找到了,否则一起向
    //上跳,找到最小的j使得他们所跳的位置不同,但父节点是相同的,返回所跳位置的父节点就好了
    #include<bits/stdc++.h>//板子
    using namespace std;
    const int maxn = 1000010;
    int head[maxn];
    int deep[maxn];//节点深度
    struct{
        int v,net;
    }edge[maxn];//链式前向星(ORZ,向大佬低头)
    int n,m,root,cnt;
    int f[maxn][21];//每个当前节点的第2 ^ j次方是哪个节点
    inline void add_edge(int x,int y)
    {   
        edge[cnt].v = y;
        edge[cnt].net = head[x];
        head[x] = cnt++;
    }//加边
    void dfs(int cur)
    {
        for(int i=head[cur];i!=-1;i=edge[i].net)
        {
            if(!deep[edge[i].v])//如果节点未被访问过
            {
                deep[edge[i].v] = deep[cur] + 1;
                f[edge[i].v][0] = cur;//父节点为cur
                dfs(edge[i].v);
            }
        }
    }//求节点的深度
    void PRE()
    {
        for(int i=1;i<=19;++i)
            for(int j=1;j<=n;++j)//n个节点预处理
                f[j][i] = f[f[j][i-1]][i-1]; //拆分二进制
    }//预处理
    int LCA(int x,int y)
    {
        if(deep[x] < deep[y])
            swap(x,y);
        for(int i=19;i>=0;--i)
        {
            if(deep[f[x][i]] >= deep[y])//上升到同一deep
                x = f[x][i];
        }
        if(x == y)
            return x;
        //否则查找最小上升的
        for(int i=19;i>=0;--i)
        {
            if(f[x][i]!=f[y][i])
            {
                x = f[x][i];
                y = f[y][i];
            }
        }
        return f[x][0];
    }
    int main()
    {
        ios::sync_with_stdio(false);    cin.tie(0),cout.tie(0);
        memset(head,-1,sizeof(head));//边集起点为 u 第一次出现的位置
        cin>>n>>m>>root;
        cnt = 1;
        int u,v;
        for(int i=1;i!=n;++i)//树有n-1条边,且为双向,因为得求深度,还得向上跳
        {
            cin>>u>>v;
            add_edge(u,v);
            add_edge(v,u);
        }
        deep[root] = 1;//根的深度为1
        dfs(root);
        PRE();
        for(int i=1;i<=m;++i)
        {
            cin>>u>>v;
            cout<<LCA(u,v)<<'
    ';
        }
    }
    不怕万人阻挡,只怕自己投降。
  • 相关阅读:
    71 是否同一棵二叉搜索树(25 分)
    75 平衡二叉树的根(25 分)
    72 树种统计(25 分)
    2018(容斥定理 HDU6286)
    直观的理解计算机中的数值编码
    如何关闭emacs开启时自己打开的欢迎界面
    图论:最短路径:广度优先搜索(C语言实现)
    ubunut 14.04 将Caps Lock设置为Control
    邻接表:C语言实现
    队列(C语言实现)
  • 原文地址:https://www.cnblogs.com/newstartCY/p/11618941.html
Copyright © 2011-2022 走看看