hdu 2586 How far away ?(Tarjan离线LCA)

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

题意:对于一个有 n 个节点的图,有 n - 1 条无向边,权值给出。有 m 个查询, 每个查询 a b 表示询问 a b 两节点间的距离。

思路:

  把这个联通图以树的形式表现出来,取任意两点,假设其最近公共祖先(Least Common Ancestors)为 lca,则两点间的距离等于:

dis(a, b) = dis(a, root) + dis(b, root) - 2 * dis(root, lca);              //root为根,每个点到 root 的距离可以在找 LCA 过程中很容易得到。

LCA和代码  (标号对应代码里的注释):

  (1)对图的存储,采用链式前向星。

  (2)Tarjan lca离线算法,需要知道所有的查询,然后运算。所以需要把询问以及答案存储。

  (3)使用到并查集。dis用来存储每个节点到 root 的距离, vis用来标记已访问过的节点(已经递归完成的节点,和当前查询节点的祖先节点),

已经访问过的点可以查询。in用来记录节点的入度, 方便找到 root。

  (4)递归形式的并查集查找操作函数(带路径压缩)。

  (5)LCA算法函数:首先明确函数的功能,对以 u 为根节点的树,找到所有以树内子节点为 a,以已访问节点为 b的查询的解。

      1:设 u 为当前集合的根节点(仅有元素 u ),标记已访问。

      2:对 u 的每个子节点递归LCA操作,之后将其加入集合,作为子节点。

      3:查询以 u 为 a,以访问节点为 b的解。(注意如果 b 并未被访问过,则无法查询,所以有了(6))

  (6)当在查询 a 时,出现 b 并未被访问情况的时候,(a,b)查询就无效了,但是 b 点在后面的过程中,总会被访问,所以当查询 b 时, a 已经访问,

此时有解。且(a,b),(b, a)查询对应结果相同,所以在输入的时候,要作这一步的处理,输出的时候判断有效解并输出即可。

代码:

时间复杂度为 n  * q;

  1 #include <stdio.h>
  2 #include <queue>
  3 #include <math.h>
  4 #include <string.h>
  5 #include <algorithm>
  6 using namespace std;
  7
  8 const int N = 100007;
  9
 10 struct Edge                                                                        //(1)
 11 {
 12     int to;
 13     int w;
 14     int next;
 15 }edge[N];
 16
 17 struct Query                                                                       //(2)
 18 {
 19     int u;
 20     int v;
 21     int ans;
 22 }query[N];
 23
 24 int pre[N], n, q, head[N], vis[N], in[N], dis[N];                       //(3)
 25
 26 int find(int r)                                                                        //(4)
 27 {
 28     if (pre[r] == r)
 29         return r;
 30     else
 31         return pre[r] = find(pre[r]);
 32 }
 33
 34 int merge(int u, int v)
 35 {
 36     int fu = find(u);
 37     int fv = find(v);
 38     if (fu != fv)
 39         pre[fv] = fu;
 40 }
 41
 42 void lca(int u)                                                                       //(5)
 43 {
 44     vis[u] = 1;
 45     pre[u] = u;
 46     for (int r = head[u]; r != -1; r = edge[r].next)
 47     {
 48         int v = edge[r].to;
 49         dis[v] = dis[u] + edge[r].w;
 50         lca(v);
 51         merge(u, v);
 52     }
 53     for (int i = 0; i < 2 * q; i++)
 54     {
 55         int uu = query[i].u;
 56         int v = query[i].v;
 57         if (uu == u && vis[v])
 58         {
 59             int lca = find(v);
 60             int res = dis[uu] + dis[v] - 2 * dis[lca];
 61             query[i].ans = res;
 62         }
 63     }
 64 }
 65
 66 int main()
 67 {
 68     int t;
 69     while (scanf("%d", &t) != EOF)
 70     {
 71         while (t--)
 72         {
 73             scanf("%d%d", &n, &q);
 74             memset(in, 0, sizeof(in));
 75             memset(vis, 0, sizeof(vis));
 76             memset(head, -1, sizeof(head));
 77             memset(dis, 0, sizeof(dis));
 78             for (int i = 0; i < n - 1; i++)
 79             {
 80                 int u, v, w;
 81                 scanf("%d%d%d", &u, &v, &w);
 82                 edge[i].to = v;
 83                 edge[i].w = w;
 84                 edge[i].next = head[u];
 85                 head[u] = i;
 86                 in[v]++;
 87             }
 88             for (int i = 0; i < q; i++)                                              //(6)
 89             {
 90                 scanf("%d%d", &query[2*i].u, &query[2*i].v);
 91                 query[2*i+1].u = query[2*i].v;
 92                 query[2*i+1].v = query[2*i].u;
 93             }
 94             int root;
 95             for (int i = 1; i <= n; i++)
 96             {
 97                 if (!in[i])
 98                     root = i;
 99             }
100             lca(root);
101             for (int i = 0; i < q; i++)
102             {
103                 int maxx = max(query[2*i].ans, query[2*i+1].ans);
104                 printf("%d\n", maxx);
105             }
106         }
107     }
108     return 0;
109 }
时间: 2024-11-03 21:52:56

hdu 2586 How far away ?(Tarjan离线LCA)的相关文章

HDU 2586 How far away ? 离线lca模板题

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

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): 6422    Accepted Submission(s): 2411 Problem Description There are n houses in the village and some bidirectional roads connecting

hdoj 2586 How far away ? 【Tarjan离线LCA】

题目:hdoj 2586 How far away ? 题意:给出一个有权树,求任意两点的之间的距离. 分析:思想就是以一个点 root 作为跟变成有根数,然后深搜处理处所有点到跟的距离.求要求的两个点的LCA(最近公共祖先), 然后ans = dis[x] + dis[y] - 2 * dis[LCA(x,y)],可以画图分析一下就知道. 求LCA我用的是Tarjan离线lca,由于询问次数很多,所以这个比较快. AC代码: #include <iostream> #include <

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> #includ

HDU 2586 How far away ?(LCA模板 近期公共祖先啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 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

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 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

SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perform the following operation: u v k : ask for the kth minimum weight on the path from node u 

HDU 2586 How far away ?(LCA在线算法实现)

http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:给出一棵树,求出树上任意两点之间的距离. 思路: 这道题可以利用LCA来做,记录好每个点距离根结点的距离,然后只要计算出两点的LCA,这样一来答案就是distance[u]+distance[v]-2distance[LCA]. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #includ

ZOJ Problem Set - 3195 Design the city 【Tarjan离线LCA】

题目:ZOJ Problem Set - 3195 Design the city 题意:给出一个图,求三点的连起来的距离. 分析:分别求出三点中任意两点的距离 / 2  = ans AC代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; #define N 50010 #define M 20010 struc