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)<<'
    ';
        }
    }
    不怕万人阻挡,只怕自己投降。
  • 相关阅读:
    高并发的epoll+线程池,epoll在线程池内ehyyngpChinaUnix博客
    用vim处理字符的大小写转换
    jabberd14 XMPP/Jabber server daemon
    thriftmissingguide/
    高并发的epoll+多线程ehyyngpChinaUnix博客
    大讲堂
    [基于Epoll内置LeaderFollower服务端实现, 已可达50万echo qps(全新支持Lua啦)] C/C++ ChinaUnix.net
    来说说epoll+线程池
    boost高并发网络框架+线程池ehyyngpChinaUnix博客
    高并发的epoll+线程池,业务在线程池内ehyyngpChinaUnix博客
  • 原文地址:https://www.cnblogs.com/newstartCY/p/11618941.html
Copyright © 2011-2022 走看看