zoukankan      html  css  js  c++  java
  • HDU2586 How far away? —— 倍增LCA

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586


    How far away ?

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 16425    Accepted Submission(s): 6252


    Problem Description
    There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
     

    Input
    First line is a single integer T(T<=10), indicating the number of test cases.
      For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
      Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
     

    Output
    For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
     

    Sample Input
    2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
     

    Sample Output
    10 25 100 100




    题解:

    1.可知这是一棵无根树,那么把它转化为有根树,再用倍增LCA求出每个结点到根节点的距离。

    2.两点的距离:dist = dis[u] + dis[v] - 2 * dis[ LCA(u,v) ]。

    3.复杂度O(nlogn)。


    对倍增LCA的理解:

    对于每一个结点,由于在倍增的时候,每个祖先以及每条边只会被扫过一次,不会出现重复,所以可以用倍增LCA求距离。



    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <string>
    #include <set>
    #define ms(a,b) memset((a),(b),sizeof((a)))
    using namespace std;
    typedef long long LL;
    const int INF = 2e9;
    const LL LNF = 9e18;
    const int mod = 1e9+7;
    const int maxn = 4e4+10;
    const int DEG = 20;
    
    int n, m;
    
    struct edge
    {
        int to, w, next;
    }edge[maxn*2];
    int head[maxn], tot;
    int fa[maxn][DEG], deg[maxn], dis[maxn];
    
    void add(int u, int v, int w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    void bfs(int root)  //一边建树,一边求出每个节点到根节点的距离,以及深度
    {
        queue<int>que;
        deg[root] = 0;
        dis[root] = 0;
        fa[root][0] = root;
        que.push(root);
        while(!que.empty())
        {
            int tmp = que.front();
            que.pop();
            for(int i = 1; i<DEG; i++)
                fa[tmp][i] = fa[fa[tmp][i-1]][i-1];
            for(int i = head[tmp]; i!=-1; i = edge[i].next)
            {
                int v = edge[i].to, w = edge[i].w;
                if(v==fa[tmp][0]) continue;
                deg[v] = deg[tmp]+1;
                dis[v] = dis[tmp]+w;
                fa[v][0] = tmp;
                que.push(v);
            }
        }
    }
    
    int LCA(int u, int v)
    {
        if(deg[u]>deg[v]) swap(u,v);
        int hu = deg[u], hv = deg[v];
        int tu = u, tv = v;
        for(int det = hv-hu, i = 0; det; det>>=1, i++)
            if(det&1)
                tv = fa[tv][i];
        if(tv==tu) return tu;
        for(int i = DEG-1; i>=0; i--)
        {
            if(fa[tu][i]==fa[tv][i]) continue;
            tu = fa[tu][i];
            tv = fa[tv][i];
        }
        return fa[tu][0];
    }
    
    int main()
    {
        int T;
        cin>>T;
        while(T--)
        {
            tot = 0;
            ms(head, -1);
            scanf("%d%d",&n,&m);
            for(int i = 1; i<n; i++)
            {
                int u, v, w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
                add(v,u,w);
            }
    
            bfs(1);
            for(int i = 0; i<m; i++)
            {
                int u, v;
                scanf("%d%d",&u,&v);
                printf("%d
    ", dis[u]+dis[v]-2*dis[LCA(u,v)]);
            }
        }
    }
    


  • 相关阅读:
    js/jquery 页面传值
    php 连接sqlserver方法
    php 写webservice常见问题
    php 解决json_encode中文null和UNICODE转码问题
    手机web——自适应网页设计
    50个js技巧(分享)
    php webservice客户端和服务器端
    php 文件下载功能
    es6 字符串的扩展
    vue $emit抛出事件
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538644.html
Copyright © 2011-2022 走看看