hdu--2586--lca_tarjan<证明tarjan这个人很流弊>

开篇 敬仰下 大师-tarjan 发明的这些算法太流弊了=-=使用这个lca_tarjan之前 可以先去学习下使用tarjan解决scc强连通问题

我本来是去做到hdu-4912-发现做不来=-= 去网上搜了下 都说是神马lca的....那就去学下吧 而且很多也将这题当做入门题..

lca分离线和在线 这边我介绍的是离线算法 是要先将所有的询问一起处理 而不是单个单个地去处理  处理完成之后 你自己选择一种方式将答案存储下来

然后再进行一遍输出答案

我再网上没有找到一篇好的博客来推荐给大家 所以这边我就不写 传送门的故事了 -.-

学习下它 对于你的思想 是很有帮助的 很多时候 都是这样

这边我们需要用到 并查集来优化这个算法

我们结合下图 进行分析

现在 我们以上图为例 建立的边<无向>

1<-->2   2<-->3   2<--->4   3<--->5   5<--->7   2<--->4  4<--->6  1<--->8  8<--->9

我们的询问就是

lca:<2,3>  ,   <5,6>    ,    <7,4>      ,    <9,3>

这4组查询结果也算都是有一些特点的吧  虽然我们很容易地可以从上图中得到结果

2 3肯定是2啊 因为3是2的子树下的结点

5 6就是2了 他们同时是2的子树的结点 你也当然会说他们也是1的子树的结点啊 但是2的深度更大 离根结点更远

还有2个就先不说了.....

既然 这是树 那我们解决的时候首先就自己确定一个根结点 按习惯上 我们都喜欢默认1当做根结点 当然你也可以2 3 ……n

草。。我突然发现 不会分析下去了..

就是要注意下 假设你当前访问到的结点是u 现在有一个结点是v与u相邻 那么假如v没有被访问过 那就再lca_tarjan(v)即去访问v 这边的后续操作要明白 既然u与v相邻 那我们可以将他们看成是在同一棵子树上的 所以我们将v所在的集合并在u所在的集合之下 这时 就需要用到并查集了  这边一定是要 father[ find(v) ] = find(u) 当然这个指向的前提是u v的find后不属于同一个集合

可能有些 言不达意 =-= 都是自我理解 大家可以多参考一些博客 然后自己模拟画画 就是了

  1 #include <iostream>
  2 #include <cstring>
  3 using namespace std;
  4
  5 int cnt1 , cnt2;
  6 const int size1 = 40010;
  7 const int size2 = 210;
  8 struct graph
  9 {
 10     int from;
 11     int to;
 12     int val;
 13     int next;
 14     int lca;
 15 };
 16 graph edge[size1*2];
 17 int Ehead[size1];
 18 graph node[size2*2];
 19 int Nhead[size1];
 20 bool vis[size1];
 21 int dist[size1];
 22 int father[size1];
 23
 24 void init( )
 25 {
 26     memset( Ehead , -1 , sizeof(Ehead) );
 27     memset( Nhead , -1 , sizeof(Nhead) );
 28     memset( dist , 0 , sizeof(dist) );
 29     memset( vis , false , sizeof(vis) );
 30 }
 31
 32 int find( int x )
 33 {
 34     return x == father[x] ? x : father[x] = find( father[x] );
 35 }
 36
 37
 38 void addEdge( int from , int to , int val )
 39 {
 40     edge[cnt1].to = to;
 41     edge[cnt1].val = val;
 42     edge[cnt1].next = Ehead[from];
 43     Ehead[from] = cnt1 ++;
 44 }
 45
 46 void addQueryEdge( int from , int to )
 47 {
 48     node[cnt2].from = from;
 49     node[cnt2].to = to;
 50     node[cnt2].next = Nhead[from];
 51     Nhead[from] = cnt2 ++;
 52 }
 53
 54 void lca_tarjan( int u , int val )
 55 {
 56     int v , x , y;
 57     vis[u] = true;
 58     dist[u] = val;
 59     father[u] = u;
 60     for( int i = Ehead[u] ; ~i ; i = edge[i].next )
 61     {
 62         v = edge[i].to;
 63         if( !vis[v] )
 64         {
 65             lca_tarjan( v , edge[i].val + val );
 66             x = find(u);
 67             y = find(v);
 68             if( x!=y )
 69             {
 70                 father[y] = x;
 71             }
 72         }
 73     }
 74     for( int i = Nhead[u] ; ~i ; i = node[i].next )
 75     {
 76         v = node[i].to;
 77         if( vis[v] )
 78         {
 79             node[i].lca = node[i^1].lca = find(v);
 80         }
 81     }
 82 }
 83
 84 int main()
 85 {
 86     cin.sync_with_stdio(false);
 87     int t , from , to , val , ans , id;
 88     int n , m;
 89     cin >> t;
 90     while( t-- )
 91     {
 92         init( );
 93         cin >> n >> m;
 94         cnt1 = cnt2 = 0;
 95         for( int i = 1 ; i<n ; i++ )
 96         {
 97             cin >> from >> to >> val;
 98             addEdge( from , to , val );
 99             addEdge( to , from , val );
100         }
101         for( int i = 0 ; i<m ; i++ )
102         {
103             cin >> from >> to;
104             addQueryEdge( from , to );
105             addQueryEdge( to , from );
106         }
107         lca_tarjan( 1 , 0 );
108         for( int i = 0 ; i<m ; i++ )
109         {
110             id = i * 2;
111             ans = dist[ node[id].from ] + dist[ node[id].to ] - 2*dist[ node[id].lca ];
112             cout << ans << endl;
113         }
114     }
115     return 0;
116 }

忘了一个很重要的...lca是基于 无向无环图的 也可以说多叉树吧 我是觉得差不多的

today:

  我们最大的敌人就是自己

  我们的恐惧来源于对自己的否定

  信心才是最重要的

时间: 2024-10-12 15:03:42

hdu--2586--lca_tarjan<证明tarjan这个人很流弊>的相关文章

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

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

HDU 2586 How far away?

http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:给定一个图,有M个询问.每一次询问为询问u,v两个点的距离为多少? 题解:LCA问题. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cmath> 6 #include <string> 7

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 2586 + HDU 4912 最近公共祖先

先给个LCA模板 HDU 1330(LCA模板) #include <cstdio> #include <cstring> #define N 40005 struct Edge{ int x,y,d,ne; }; Edge e[N*2],e2[N*2]; int be[N],be2[N],all,all2,n,m; bool vis[N]; int fa[N]; int ancestor[N][3]; int dis[N]; void add(int x, int y, int

hdu 2586 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 B&quo

HDU 2586 LCA-Tarjan

还是LCA-tarjan算法,跟POJ 1330做法基本类似,只是这个题目要求输出两个点的最短距离,其实利用LCA的性质,就是 两个点分别到最近公共祖先的距离之和 一开始本来想用并查集把路径长度给找出来,但是不太好处理,原因是我刚好找到的这个点还没有加入到并查集中,(因为还没回溯上去),如果马上就合并,我还得把父亲传下来,还破坏了原有算法的结构(在孩子这里就进行了并查集合并操作),会产生奇怪的结果... 有个很简便又机智的方法,就是在dfs的过程中 一边记录从rt到下面的点的距离dis,假设 A

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 ?

先上题目: How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4936    Accepted Submission(s): 1866 Problem Description There are n houses in the village and some bidirectional roads conne

HDU 4923 (贪心+证明)

Room and Moor Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0 or 1. In order to beat him, programmer Moor has to construct another sequence B = {B1, B2,... , BN} of the same length, which satisfies that: