hdu 2586 How far away ?倍增LCA

hdu 2586 How far away ?倍增LCA

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=2586

思路:

  • 针对询问次数多的时候,采取倍增求取LCA,同时跟新距离数组
  • 因为
  • \(2^{16} > 40000\)
  • 所以所以表示祖先的数组dp[][]第二维取到16即可
  • 就这道题来说,与比较tarjan比较,稍快一点

    代码:

    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    using namespace std;
    const int maxn = 40005;
    const int maxm = 80005;
    struct node {
    int to,next,w;
    }edges[maxm];
    int head[maxn],cnt,dp[maxn][17],dep[maxn],dist[maxn];
    inline void addedge(int u, int v, int w) {
    edges[cnt].to=v;
    edges[cnt].w=w;
    edges[cnt].next=head[u];
    head[u]=cnt++;
    }
    void dfs(int s, int x) {
    dp[s][0]=x;
    dep[s]=dep[x]+1;
    int t;
    for(int i=1;(1<<i)<=dep[s];++i)
        dp[s][i]=dp[dp[s][i-1]][i-1];
    for(int i=head[s];i!=-1;i=edges[i].next) {
        t=edges[i].to;
        if(t==x) continue;
        dist[t]=dist[s]+edges[i].w;
        dfs(t,s);
    }
    }
    inline int lca(int u, int v) {
    if(dep[v]>dep[u]) swap(u,v);
    for(int i=16;i>=0;--i) {
        if((1<<i)<=(dep[u]-dep[v])) {
            u=dp[u][i];
        }
    }
    if(u==v) return u;
    for(int i=16;i>=0;--i) {
        if((1<<i)<=dep[u]&&(dp[v][i]!=dp[u][i])) {
            u=dp[u][i];
            v=dp[v][i];
        }
    }
    return dp[u][0];
    }
    inline int slove(int u ,int v) {
    int z=lca(u,v);
    return dist[u]-2*dist[z]+dist[v];
    }
    inline void init() {
    cnt=0;
    memset(head,-1,sizeof(head));
    }
    int main() {
    int t,n,m,u,v,w;
    scanf("%d",&t);
    while(t--) {
        scanf("%d %d",&n,&m);
        init();
        for(int i=1;i<n;++i) {
            scanf("%d %d %d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dep[1]=0;//保持dfs的统一,实际dep[1]=1
        dist[1]=0;
        dfs(1,1);
        for(int i=1;i<=m;++i) {
            scanf("%d %d",&u,&v);
            printf("%d\n",slove(u,v));
        }
    }
    return 0;
    }
时间: 2024-10-04 13:12:29

hdu 2586 How far away ?倍增LCA的相关文章

HDU 2586 How far away ? (LCA最近公共祖先)

题目地址:HDU 2586 LCA第一发. 纯模板题. 偷懒用的vector,结果一直爆栈.把G++改成C++就过了.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <se

HDU 2887 Watering Hole(MST + 倍增LCA)

传送门 总算是做上一道LCA的应用题了... 题意:有$n$个牧场, $m$根管道分别连接编号为$u,v$的牧场花费$p_{i}$,在第$i$个牧场挖口井需要花费$w_{i}$,有$P$根管道直接连通着$u,v$,即免费连上$u,v$ 对每根免费管道输出让所有牧场都有水的最小花费 先是最小生成树,用0去连每一个点,边权就是每个点的权值,然后正常建,跑一遍最小生成树,把用到的边重新建一次图,然后就对每次询问的$u,v$,减掉他们之间的路径的最长边就是答案了 因为删去这其中一条边,再免费连上$u,v

【HDU 2586 How far away?】LCA问题 Tarjan算法

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:给出一棵n个节点的无根树,每条边有各自的权值.给出m个查询,对于每条查询返回节点u到v的最短路径的权值和,按查询顺序输出结果. 数据范围:n [2, 40000], m[1, 200] 思路:Tarjan算法:dfs遍历每个点,每遍历完 r 的一个孩子 c, 把 c 并入以 r 为祖先的集合,并处理 c 的所有查询 q:若qi的目标节点 v 已被遍历到,那么一定有lca(c, v) =

HDU 2586 How far away ?(LCA裸题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 #include<bits/stdc++.h> #define lson rt << 1, l, m #define rson rt << 1 | 1, m + 1, r using namespace std; typedef long long ll; static const ll inf = (1 << 32); static const int

hdu 2874 Connections between cities hdu 2586 How far away ? LCA

两道lca模板题,用的是倍增法,nlogn预处理,logn查询. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; #define maxn 10100 struct Edge { int u,v,w,next; }e[100100]; int n,m,c; int head[maxn],cnt; int fa[ma

HDU 2586 How far away ? &lt;&lt; LCA转RMQ+ST表 求树上任两点最短距离裸题

此题还有LCA+tarjin离线查询做法,详见这里 关于ST表 解决RMQ问题,dp[i][j]表示从第i位开始长度为(1<<j)的区间的最值 维护的时候采用倍增思想,维护dp[i][j+1]=opt(dp[i][j],dp[i+(1<<j)][j]) 查询的时候,两端点为l,r,则长度len=r-l,寻找一个k,使(1<<k)大于等于len/2,这样就使得 [l,l+(1<<k)]和[r-(1<<k),r]覆盖整个区间 然后此时,就可以直接用s

hdu 2586 How far away? (LCA模板)

题意: N个点,形成一棵树,边有长度. M个询问,每个询问(a,b),询问a和b的距离 思路: 模板题,看代码.DFS预处理算出每个结点离根结点的距离. 注意: qhead[maxn],而不是qhead[maxm]. 输出用%I64d,不要用%lld. C++ RE后 尝试用 G++交. 代码: struct node{ int to,w,next,lca; }; int const maxn = 40005; int const maxm = 205; int fa[maxn]; int he

HDU - 2586 How far away ?(LCA)

题目大意:给出一张连通图,问两个点之间的距离 解题思路:LCA裸题 #include <cstdio> #include <cstring> #define N 40010 #define M 80010 struct Edge{ int to, next, dis; }E[M]; struct Question { int x, y; }Q[N]; int n, m ,tot; int head[N], dist[N], f[N], LCA[N]; bool vis[N]; vo

HDU 2586 How far away ? (LCA,Tarjan, spfa)

题意:给定N个节点一棵树,现在要求询问任意两点之间的简单路径的距离,其实也就是最短路径距离. 析:用LCA问题的Tarjan算法,利用并查集的优越性,产生把所有的点都储存下来,然后把所有的询问也储存下来,然后从树根开始搜索这棵树, 在搜索子树的时候,把并查集的父结点不断更新,在搜索时计算答案,d[i] 表示从根结点到 i 结点的距离,然后分别计算到两个结点的距离, 再减去2倍的根结点到他们公共最近的结点距离,就OK了.不过这个题有个坑人的地方,不用输出那个空行,否则就是PE. 因为这个题询问比较

hdu 2586 How far away ? ( 离线 LCA , tarjan )

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10312    Accepted Submission(s): 3743 Problem Description There are n houses in the village and some bidirectional roads connecting