HDU2586 How far away ?【最近公共祖先】【Tarjan-LCA算法】

How far away ?

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 6252    Accepted Submission(s): 2344

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

Source

ECJTU 2009 Spring Contest

题目大意:一个村庄有N个房子和一些双向的路,人们总是喜欢问"A到B有多远呢",一般是很难

回答的,毕竟有很多种答案。所幸,答案是唯一的,A到B总是有唯一的路径到达。第一行是T组

数据。每组数据第一行是N个房子和M条询问。接下来N-1行每行是u v w,表示从房子u到房子v

的距离是w。接下来是M行询问。每行是u v,表示询问房子u到房子v的距离,最后输出所有的询

问结果。

思路:整个村庄房子和路可看成一棵树,设根结点为房子1,询问u到房子v的距离,其实就是求u

到根结点的距离 + v到根结点的距离 - 2*(u,v)最近公共祖先到根结点的距离。这道题和POJ1986

是一样的,可参考:http://blog.csdn.net/lianai911/article/details/42300301

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 80080;
const int MAXQ = 440;

struct EdgeNode
{
    int to;
    int next;
    int lca;
}Edges[MAXN],QEdges[MAXQ];

int Head[MAXN],QHead[MAXN],father[MAXN],Dist[MAXN];
bool vis[MAXN];

int find(int x)
{
    if(x != father[x])
        father[x] = find(father[x]);
    return father[x];
}

void LCA(int u)
{
    father[u] = u;
    vis[u] = true;
    for(int k = Head[u]; k != -1; k = Edges[k].next)
    {
        if(!vis[Edges[k].to])
        {
            Dist[Edges[k].to] = Dist[u] + Edges[k].lca;
            LCA(Edges[k].to);
            father[Edges[k].to] = u;
        }
    }
    for(int k = QHead[u]; k != -1; k = QEdges[k].next)
    {
        if(vis[QEdges[k].to])
        {
            QEdges[k].lca = Dist[u] + Dist[QEdges[k].to] - 2*Dist[find(QEdges[k].to)];
            QEdges[k^1].lca = QEdges[k].lca;
        }
    }
}

int main()
{
    int T,N,M,u,v,w;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        memset(Dist,0,sizeof(Dist));
        memset(father,0,sizeof(father));
        memset(vis,false,sizeof(vis));
        memset(Edges,0,sizeof(Edges));
        memset(QEdges,0,sizeof(QEdges));
        memset(Head,-1,sizeof(Head));
        memset(QHead,-1,sizeof(QHead));
        int id = 0;
        for(int i = 0; i < N-1; ++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            Edges[id].to = v;
            Edges[id].lca = w;
            Edges[id].next = Head[u];
            Head[u] = id++;
            Edges[id].to = u;
            Edges[id].lca = w;
            Edges[id].next = Head[v];
            Head[v] = id++;
        }
        int ip = 0;
        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d",&u,&v);
            QEdges[ip].to = v;
            QEdges[ip].next = QHead[u];
            QHead[u] = ip++;
            QEdges[ip].to = u;
            QEdges[ip].next = QHead[v];
            QHead[v] = ip++;
        }
        LCA(1);
        for(int i = 0; i < ip; i += 2)
            printf("%d\n",QEdges[i].lca);
    }
    return 0;
}
时间: 2024-10-11 17:35:36

HDU2586 How far away ?【最近公共祖先】【Tarjan-LCA算法】的相关文章

笔记:LCA最近公共祖先 Tarjan(离线)算法

LCA最近公共祖先 Tarjan他贱(离线)算法的基本思路及其算法实现 本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig/article/details/52336496 https://baike.baidu.com/item/最近公共祖先/8918834?fr=aladdin 最近公共祖先简称LCA(Lowest Common Ancesto

最近公共祖先 tarjan离线算法 C++

最近做到一道题目,大概的意思就是求一个多叉树中两个节点的最近公共祖先,输入是用邻接矩阵表示的. 要想理解tarjan算法并实现它,需要先理解一下内容: 1) 深度优先搜索:tarjan算法核心思想:当某节点刚刚搜索完毕时,看与其相关的结点v是否已经被访问,如果v已经被访问过了,则它们的最近公共祖先就是v的祖先. 2) 并查集原理和实现方法,并查集的代表和祖先的区别(其实也可以一起表示),祖先的更新时刻 3) 如何表示多叉数(邻接链表,邻接矩阵),如何表示查询对,如何记录查询结果 下面是c++实现

LCA最近公共祖先 Tarjan离线算法

学习博客:  http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点(B)(及要求的最近祖先的另一个点)之前被访问过,那么 B可定已经属于一个集合,先前对于访问过的点,已经维护了那个点所在集合的根,所以找到B节点所在集合的根,那么这个点就是最近的根,因为对于dfs访问的顺序.

最近公共祖先(LCA)---tarjan算法

LCA(最近公共祖先).....可惜我只会用tarjan去做 真心感觉tarjan算法要比倍增算法要好理解的多,可能是我脑子笨吧略略略 最近公共祖先概念:在一棵无环的树上寻找两个点在这棵树上深度最大的公共的祖先节点,也就是离这两个点最近的祖先节点. 最近公共祖先的应用:求解两个有且仅有一条确定的最短路径的路径 举个例子吧,如下图所示4和5的最近公共祖先是2,5和3的最近公共祖先是1,2和1的最近公共祖先是1. 这就是最近公共祖先的基本概念了,那么我们该如何去求这个最近公共祖先呢? Tarjan介

最近公共祖先(lca)

囧啊囧. lca的求法太多了 倍增,tarjan,st,lct,hld.... 后边三个我就不写了,其中st我没写过,估计用不上,在线用倍增,离线用tarjan就行了. 嗯. 第一种,倍增(nlogn,在线): 倍增的思想用在树上,即可以求出lca. 我们维护二维数组,f[i][j],表示i号点的第2^j号祖先,显然2^0=1也就是f[i][0]就是他的父亲 我们需要用dfs维护一个深度数组(求lca需要用) 还需要倍增求出所有的f[i][j],学过st的都应该知道,在这里f[i][j]=f[

洛谷P3379 【模板】最近公共祖先(LCA)

P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有倍- 题面这个地方写错了 无论是用RMQ+dfs还是tarjan- 为什么我的倍增超时了 求助!为什么只有70分 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接

【原创】洛谷 LUOGU P3379 【模板】最近公共祖先(LCA) -&gt; 倍增

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入

洛谷 P3379 【模板】最近公共祖先(LCA) 如题

P3379 [模板]最近公共祖先(LCA) 时空限制1s / 512MB 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询

luogo p3379 【模板】最近公共祖先(LCA)

[模板]最近公共祖先(LCA) 题意 给一个树,然后多次询问(a,b)的LCA 模板(主要参考一些大佬的模板) #include<bits/stdc++.h> //自己的2点:树的邻接链表(静态)表示; lca 的倍增算法 //优化 log[] const int maxn=500010; int N,M,S;//S根节点标号 int head[maxn];//head[i]=k 以i为起点的第一条边是edge[k] int dep[maxn],dp[maxn][21];//dp[i][j]

P3379 【模板】最近公共祖先(LCA)(dfs序)

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入