码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-08-13 12:45:07      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

题目链接: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 }

 

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

标签:

原文地址:http://www.cnblogs.com/burning-flame/p/maoguanghui_suibi_lca.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!