• 距离LCA离线算法Tarjan + dfs + 并查集


    距离B - Distance in the Tree

    还是普通的LCA但是要求的是两个节点之间的距离,学到了一些

    一开始我想用带权并查集进行优化,但是LCA合并的过程晚于离线计算的过程,所以路径长度会有所偏差

    所以失败告终

    网上查询之后懂得要提前进行一下预处理,在输入完全部的边之后,也就是数形成之后,计算dis——》也就是每个点到树根的长度

    之后进行询问查询时:u,v 和 rt 这样uv的距离就是dis[u] + dis[v] - 2 * dis[rt]很好理解

    时间复杂度也还可以

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    using namespace std;
    const int maxn = 5e4 + 50;
    const int maxm = 7e4 + 6e3;
    int id[maxn],qid[maxn];
    int cnt,qcnt;
    int pre[maxn],cost[maxn];
    int vis[maxn];
    struct node{
        int to,pre,cost;
    }e[maxn * 2];
    struct node2{
        int to,ads,pre;
    }q[maxm * 2];
    int ans[maxm];
    int Find(int x)
    {
        //cout<<x<<endl;
        if(pre[x] == x)return x;
        else
        {
            //cost[x] += cost[pre[x]];
            return pre[x] = Find(pre[x]);
        }
    }
    
    void join(int a,int b)
    {
        int fa = Find(a),fb = Find(b);
        if(fa != fb)
        {
            pre[fb] = fa;
        }
    }
    
    void init(int n)
    {
        for(int i = 0;i <= n;i++)
        {
            pre[i] = i;
            vis[i] = 0;
            cost[i] = 0;
        }
        memset(id,-1,sizeof(id));
        memset(qid,-1,sizeof(qid));
        cnt = qcnt = 0;
    }
    
    void add(int from,int to,int cost)
    {
        e[cnt].to = to;
        e[cnt].pre = id[from];
        e[cnt].cost = cost;
        id[from] = cnt++;
    }
    void qadd(int from,int to,int i)
    {
        q[qcnt].to = to;
        q[qcnt].ads = i;
        q[qcnt].pre = qid[from];
        qid[from] = qcnt++;
    }
    void get_cost(int rt,int dis)
    {
        vis[rt] = 1;
        cost[rt] = dis;
        for(int i = id[rt];~i;i = e[i].pre)
        {
            int to = e[i].to;
            int cos = e[i].cost;
            if(!vis[to])
            {
                get_cost(to,dis+cos);
            }
        }
    }
    void tarjan(int rt)
    {
        //cout<<rt<<endl;
        vis[rt] = -1;
        for(int i = id[rt];~i;i = e[i].pre)
        {
            int to = e[i].to;
            int cos = e[i].cost;
            if(!vis[to])
            {
                tarjan(to);
                join(rt,to);
            }
            //cout<<"cs"<<to<<" "<<cost[to]<<endl;
        }
    
        vis[rt] = 1;
        for(int i = qid[rt];~i;i = q[i].pre)
        {
            int to = q[i].to;
            if(vis[to] == 1)
            {
                //cout<<"to :   "<<to<<endl;
                //cout<<"pre[to]:  "<<pre[to]<<endl;
                //cout<<rt<<" "<<to<<"cost: "<<cost[rt]<<" "<<cost[to]<<endl;
                int lca = Find(to);
                ans[q[i].ads] = abs(cost[lca] - cost[rt]) + abs(cost[lca] - cost[to]);
            }
        }
    }
    int main()
    {
        int n,m,u,v,w;
        scanf("%d",&n);
        init(n);
        for(int i = 1;i < n;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        get_cost(0,0);
        memset(vis,0,sizeof(vis));
        scanf("%d",&m);
        for(int i = 1;i <= m;++i)
        {
            scanf("%d%d",&u,&v);
            qadd(u,v,i);
            qadd(v,u,i);
        }
        tarjan(0);
        for(int i = 1;i <= m;++i)
        {
            printf("%d
    ",ans[i]);
        }
        return 0;
    }
    /*
    7
    0 1 1
    0 2 1
    0 3 1
    1 4 1
    2 5 1
    2 6 1
    40
    0 1
    0 2
    0 3
    0 4
    0 5
    0 6
    0 0
    1 1
    1 2
    1 3
    1 4
    1 5
    1 6
    1 0
    2 0
    2 1
    2 2
    2 3
    2 4
    2 5
    2 6
    3 0
    3 1
    3 2
    3 3
    3 4
    3 5
    3 6
    4 0
    4 1
    4 2
    4 3
    4 4
    4 5
    4 6
    5 0
    5 1
    5 2
    5 3
    5 4
    */
    
  • 相关阅读:
    CentOS 7/8修改系统运行级别
    Sketchup 汇总
    [转]Ruby之类的真相
    [转]Ruby之代码块的迷思
    [转]ruby中的异常处理
    [转]ruby中Class的allocate
    [转]ruby中require和load的区别
    [转]ruby之方法查找
    [转]ruby之动态方法
    [转] ruby之对象体系
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9431964.html
Copyright © 2020-2023  润新知