zoukankan      html  css  js  c++  java
  • hdu 2586 欧拉序+rmq 求lca

    题意:求树上任意两点的距离

    先说下欧拉序

    对这颗树来说 欧拉序为 ABDBEGBACFHFCA 那欧拉序有啥用

    这里先说第一个作用 求lca

    对于一个欧拉序列,我们要求的两个点在欧拉序中的第一个位置之间肯定包含他们的lca,因为欧拉序1上任意两点之间肯定包含从第一个点走到第二个点访问的路径上的所有点

    所以只需要记录他们的深度,然后从两个询问子节点x,y第一次出现的位置之间的深度最小值即可,可能不大好理解,看张图吧。

    也就是说求lca可以转换为求一段区间的最值问题,结合rmq就可以处理啦

    对于2586这题有个结论:树上任意两个点的距离等于两个点到根的距离之和减去2倍lca到根的距离

    上代码

    #include <cstdio>
    #include <iostream>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    struct node
    {
        int x;
        ll cost;
    };
    vector<node> edge[40010];
    ll dis[40010];// 到根节点的距离
    int dep[80010];
    int ver[80010];// 欧拉序列
    int first[40010];// 在欧拉序中第一次出现的位置
    int vret;//
    int n,m;
    int mn[80010][20];
    void dfs(int x,int fa,int deep) // 求出欧拉序 以及每个点对应的度
    {
        ver[++vret]=x;
        first[x]=vret;
        dep[vret]=deep;
        int len=edge[x].size();
        for(int i=0;i<len;i++)
        {
            node temp=edge[x][i];
            if(temp.x!=fa)
            {
                dis[temp.x]=dis[x]+temp.cost;
                dfs(temp.x,x,deep+1);
                ver[++vret]=x;
                dep[vret]=deep; //
            }
        }
    }
    void st(int n)// 维护的是欧拉序 长度需要注意一下
    {
        int temp=(int)floor(log2(double(n)));
        for(int i=1;i<=n;i++) mn[i][0]=i;// 注意一下 这里维护的是点 不是单纯的值
        for(int j=1;j<=temp;j++)
        {
            for(int  i=1;i+(1<<j)-1<=n;i++)
            {
                int a=mn[i][j-1];
                int b=mn[i+(1<<(j-1))][j-1];
                if(dep[a] < dep[b]) mn[i][j]=a;
                else mn[i][j]=b;
            }
        }
    }
    int rmq(int x,int y)
    {
        int k=(int)(log(double(y-x+1))/log(2.0));
        int a=mn[x][k];
        int b=mn[y-(1<<k)+1][k];
        if(dep[a] < dep [b]) return a;
        else return b;
    }
    int lca(int x,int y)
    {
        int fx=first[x];
        int fy=first[y];
        if(fx>fy) swap(fx,fy);
        return  rmq(fx,fy);
    }
    void init()
    {
        vret=0;
        dis[1]=0;
        for(int i=1;i<=n;i++) edge[i].clear();
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            init();// edge
            scanf("%d %d",&n,&m);
            for(int i=1;i<n;i++)
            {
                int x,y;
                ll cost;
                scanf("%d %d %lld",&x,&y,&cost);
                node temp;
                temp.cost=cost;
                temp.x=x;
                edge[y].push_back(temp);
                temp.x=y;
                edge[x].push_back(temp);
            }
    
    
            dfs(1,1,1);//
            st(2*n-1);
    
            for(int i=1;i<=m;i++)
            {
                int x,y;
                cin>>x>>y;
                int temp=lca(x,y);// point
                cout<<dis[x]+dis[y]-2*dis[temp]<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    为什么杜蕾斯的文案工资月薪5万?
    在独立音乐上,网易云音乐是如何甩了其他音乐平台几条街?
    两次大战,为什么德国成不了世界霸主呢?
    在大城市打拼的你,是想留下还是想攒够了钱回家?
    生存在互联网公司是种怎样的体验?
    5G为何采纳华为力挺的Polar码?一个通信工程师的大实话
    放下恩怨,曝小米中兴投关键性一票让华为顺利取得5G短码控制权
    中国唯一的科技城
    互联网圈的6大奇葩大产品经理:张小龙不在乎手机碎屏,马化腾让用户一秒变白痴
    为什么说中国快递分两种:一种叫顺丰,一种叫快递?
  • 原文地址:https://www.cnblogs.com/z1141000271/p/8341664.html
Copyright © 2011-2022 走看看