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

给出一颗树和边权,询问两点距离。

考虑tarjan离线做法,做法很巧妙,当前进行到u,对他的儿子v,当v子树tarjan完成之后把v合并到u上。当遍历完所有v之后,对与u有关的询问进行查找,若第二个询问点v被访问过,那么lca(u,v)就是v目前被合并到的根上。还有记录d[u]表示根到u的距离。

  最后答案就是d[u]+d[v]-2*d[lca(u,v)]。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<map>
  5. #include<set>
  6. #include<stack>
  7. #include<deque>
  8. #include<bitset>
  9. #include<unordered_map>
  10. #include<unordered_set>
  11. #include<queue>
  12. #include<cstdlib>
  13. #include<ctype.h>
  14. #include<ctime>
  15. #include<functional>
  16. #include<algorithm>
  17. #include<bits/stdc++.h>
  18. using namespace std;
  19. #define LL long long
  20. #define pii pair<int,int>
  21. #define mp make_pair
  22. #define pb push_back
  23. #define fi first
  24. #define se second
  25. #define inf 0x3f3f3f3f
  26. #define debug puts("debug")
  27. #define mid ((L+R)>>1)
  28. #define lc (id<<1)
  29. #define rc (id<<1|1)
  30. const int maxn=;
  31. const int maxm=;
  32. const double PI=acos(-1.0);
  33. const double eps=1e-;
  34. const LL mod=1e9+;
  35. LL gcd(LL a,LL b){return b==?a:gcd(b,a%b);}
  36. LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
  37. LL qpow(LL a,LL b,LL c){LL r=; for(;b;b>>=,a=a*a%c)if(b&)r=r*a%c;return r;}
  38. template<class T>
  39. void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
  40. struct Edge{int u,v,w,next;};
  41.  
  42. vector<pii>g[maxn],q[maxn];
  43. int d[maxn],f[maxn],qu[],qv[],ans[];
  44. bool vis[maxn];
  45. int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
  46. void tarjan(int u){
  47. vis[u]=;
  48. for(pii e:g[u]){
  49. int v=e.fi,w=e.se;
  50. if(!vis[v]){
  51. d[v]=d[u]+w;
  52. tarjan(v);
  53. f[v]=u;
  54. }
  55. }
  56. for(pii e:q[u]){
  57. int v=e.fi,id=e.se;
  58. if(vis[v]){
  59. ans[id]=getf(v);
  60. }
  61. }
  62. }
  63. int main(){
  64. int t,n,m,i,j,u,v,w;
  65. scanf("%d",&t);
  66. while(t--){
  67. scanf("%d%d",&n,&m);
  68. for(i=;i<=n;++i){
  69. g[i].clear();
  70. q[i].clear();
  71. f[i]=i;
  72. vis[i]=;
  73. }
  74. for(i=;i<n;++i){
  75. scanf("%d%d%d",&u,&v,&w);
  76. g[u].pb(mp(v,w));
  77. g[v].pb(mp(u,w));
  78. }
  79. for(i=;i<=m;++i){
  80. scanf("%d%d",qu+i,qv+i);
  81. q[qu[i]].pb(mp(qv[i],i));
  82. q[qv[i]].pb(mp(qu[i],i));
  83. }
  84. tarjan();
  85. for(i=;i<=m;++i){
  86. printf("%d\n",d[qu[i]]+d[qv[i]]-*d[ans[i]]);
  87. }
  88. }
  89. return ;
  90. }

接着用ST在线做法又做了一遍。如果题目强制在线的话,tarjan做法就gg了,我们提前不知道询问便无法离线做了。

ST做法是每次访问到一个节点就记录下当前的节点值和深度,当查询lca(u,v)的时候,先找到u和v第一次访问到的位置L和R(L<=R),

然后在[L,R]中找到一个深度最小的点,他对应的节点值w=lca(u,v)。RMQ问题,使用ST处理O(nlog(n))。询问就可以O(1)啦。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<map>
  5. #include<set>
  6. #include<stack>
  7. #include<deque>
  8. #include<bitset>
  9. #include<unordered_map>
  10. #include<unordered_set>
  11. #include<queue>
  12. #include<cstdlib>
  13. #include<ctype.h>
  14. #include<ctime>
  15. #include<functional>
  16. #include<algorithm>
  17. #include<bits/stdc++.h>
  18. using namespace std;
  19. #define LL long long
  20. #define pii pair<int,int>
  21. #define mp make_pair
  22. #define pb push_back
  23. #define fi first
  24. #define se second
  25. #define inf 0x3f3f3f3f
  26. #define debug puts("debug")
  27. #define mid ((L+R)>>1)
  28. #define lc (id<<1)
  29. #define rc (id<<1|1)
  30. const int maxn=;
  31. const int maxm=;
  32. const double PI=acos(-1.0);
  33. const double eps=1e-;
  34. const LL mod=1e9+;
  35. LL gcd(LL a,LL b){return b==?a:gcd(b,a%b);}
  36. LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
  37. LL qpow(LL a,LL b,LL c){LL r=; for(;b;b>>=,a=a*a%c)if(b&)r=r*a%c;return r;}
  38. template<class T>
  39. void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
  40. struct Edge{int u,v,w,next;};
  41.  
  42. vector<pii>g[maxn];
  43. vector<int>dep,idx;
  44. int f[maxn*][],d[maxn],p[maxn];
  45. void dfs(int u,int o,int fa){
  46. p[u]=idx.size();
  47. idx.pb(u),dep.pb(o);
  48. for(pii e:g[u]){
  49. int v=e.fi,w=e.se;
  50. if(v!=fa){
  51. d[v]=d[u]+w;
  52. dfs(v,o+,u);
  53. idx.pb(u),dep.pb(o);
  54. }
  55. }
  56. }
  57. void ST(int n){
  58. for(int i=;i<n;++i)f[i][]=i;
  59. for(int j=;(<<j)<=n;j++){
  60. for(int i=;(i+(<<j)-)<n;i++){
  61. f[i][j]=dep[f[i][j-]]<dep[f[i+(<<(j-))][j-]]?f[i][j-]:f[i+(<<(j-))][j-];
  62. }
  63. }
  64. }
  65. int ask(int L,int R){
  66. int k=;
  67. while((<<(+k))<=R-L+)k++;
  68. return dep[f[L][k]]<dep[f[R-(<<k)+][k]]?idx[f[L][k]]:idx[f[R-(<<k)+][k]];
  69. }
  70. int main(){
  71. int t,n,m,i,j,u,v,w;
  72. scanf("%d",&t);
  73. while(t--){
  74. idx.clear();
  75. dep.clear();
  76. scanf("%d%d",&n,&m);
  77. for(i=;i<=n;++i){
  78. g[i].clear();
  79. }
  80. for(i=;i<n;++i){
  81. scanf("%d%d%d",&u,&v,&w);
  82. g[u].pb(mp(v,w));
  83. g[v].pb(mp(u,w));
  84. }
  85. dfs(,,);
  86. ST(idx.size());
  87. // prt(idx);
  88. // prt(dep);
  89. while(m--){
  90. scanf("%d%d",&u,&v);
  91. int L=p[u],R=p[v];
  92. if(L>R)swap(L,R);
  93. printf("%d\n",d[u]+d[v]-*d[ask(L,R)]);
  94. }
  95. }
  96. return ;
  97. }
  98. /*
  99. 5
  100. 7 7
  101. 1 2 1
  102. 1 3 1
  103. 2 4 1
  104. 2 5 1
  105. 5 6 1
  106. 5 7 1
  107. */

  综上两种方法而言,我感觉思想都是类似是,就是u-->v这条路一定经过他们的共同祖先,这中间过程中经过若干个点,我们要想办法找到深度最小的那个点,显然他只会被经过一次,就是LCA。

HDU-2586-裸LCA入门-tarjan离线的更多相关文章

  1. hdu 2586(裸LCA)

    传送门 题意: 某村庄有n个小屋,n-1条道路连接着n个小屋(无环),求村庄A到村庄B的距离,要求是经过任一村庄不超过一次. 题解: 求出 lca = LCA(u,v) , 然后答案便是dist[u] ...

  2. hdu2586(lca模板 / tarjan离线 + RMQ在线)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意: 给出一棵 n 个节点的带边权的树, 有 m 个形如 x y 的询问, 要求输出所有 x, ...

  3. 洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线

    题目链接:LCA tarjan离线 这道题目WA无数发,最后还是参考了大神的blog 谁会想到因为一个输入外挂WA呢 大概是我的挂是假挂吧...orz(其实加上外挂,速度提升很多) 用链式前向星保存边 ...

  4. POJ 1330 Nearest Common Ancestors 【最近公共祖先LCA算法+Tarjan离线算法】

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20715   Accept ...

  5. HDU 2586.How far away ?-离线LCA(Tarjan)

    2586.How far away ? 这个题以前写过在线LCA(ST)的,HDU2586.How far away ?-在线LCA(ST) 现在贴一个离线Tarjan版的 代码: //A-HDU25 ...

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

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. LCA之tarjan离线

    显然81篇题解是有点多了,不让我提交. 更为不好的是没有一篇详细的\(tarjan\)(不过我也不会写详细的). 不过\(tarjan\)并没有我们想象的那样难理解,时间也并不爆炸(巧妙的跳过难写二字 ...

  8. How far away ? HDU - 2586 【LCA】【RMQ】【java】

    题目大意:求树上任意两点距离. 思路: dis[i]表示i到根的距离(手动选根),则u.v的距离=dis[u]+dis[v]-2*dis[lca(u,v)]. lca:u~v的dfs序列区间里,深度最 ...

  9. POJ 1986 Distance Queries 【输入YY && LCA(Tarjan离线)】

    任意门:http://poj.org/problem?id=1986 Distance Queries Time Limit: 2000MS   Memory Limit: 30000K Total ...

随机推荐

  1. 2、My Scripts

    http://www.cnblogs.com/image-eye/archive/2011/10/26/2220405.html      注释详解 1.打印选择菜单,按照选择项一键安装不同的web服 ...

  2. hdu 1115 Lifting the Stone 多边形的重心

    Lifting the Stone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. java static方法不能被重写@Override

    重写方法的目的是为了多态,或者说:重写是实现多态的前提,即重写是发生在继承中且是针对非static方法的. 语法上子类允许出现和父类只有方法体不一样其他都一模一样的static方法,但是在父类引用指向 ...

  4. JSON parse error: Cannot deserialize instance of `int` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc

    代码程序: @PostMapping("selectById") @ResponseBody public Result selectById(@RequestBody int i ...

  5. C/C++.全文件名全路径名分割拆分分解

    1._splitpath ZC:windows api的话 可以使用 PathFindFileNameA.PathFindExtensionA.PathFileExistsA等一系列函数 2.测试代码 ...

  6. Vscode中运行js文件或部分代码 ,在下面cmd输出中显示结果

    重启 vscode,  这个插件  真好用,, 赞个 ....

  7. MySQL字段拼接Concat

    有时候,从数据库中拿出的数据并不是我们想要的格式,比如,有以下的vendors表 如果,想以 name (location)的格式展现出来,那么就要用到MySQL的Concat了. Concat()拼 ...

  8. eclipse创建web项目web.xml配置文件笔记

    1.使用eclipse创建web项目时,如果直接finish的话就没有默认生成web.xml配置文件,此时在你的项目下是看不到web.xml配置文件的,如果要查看的话可以如下操作: 右键你的项目,然后 ...

  9. Vim 8.0

    安装Vim 8.0yum install ncurses-devel wget https://github.com/vim/vim/archive/master.zip unzip master.z ...

  10. linux下源码安装

    ●源码的安装(./configure –prefix 命令用法)一般由3个步骤组成:配置(configure).编译(make).安装(make install). Configure是一个可执行脚本 ...