[hdu2586]How far away?(LCA)

题意:问树上两点之间的最短距离

解题关键:LCA模板题,不知道为什么在hdu g++超时,c++70ms就过了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 typedef long long ll;
 8 using namespace std;
 9 const int maxn=40010;
10 const int maxm=25;
11 int _pow[maxm],m,n;
12 int head[maxn],tot;
13 int ver[maxn*2],depth[maxn*2],first[maxn],dis[maxn],rmq[maxn*2][maxm],id;//5个数组,注意哪个需要乘2
14
15 inline int read(){
16     char k=0;char ls;ls=getchar();for(;ls<‘0‘||ls>‘9‘;k=ls,ls=getchar());
17     int x=0;for(;ls>=‘0‘&&ls<=‘9‘;ls=getchar())x=(x<<3)+(x<<1)+ls-‘0‘;
18     if(k==‘-‘)x=0-x;return x;
19 }
20
21 struct edge{
22     int to,w,nxt;
23 }e[maxn*2];//链式前向星建树
24
25 void init(){
26     memset(head,-1,sizeof head);
27     tot=0;
28     id=0;
29 }
30
31 void add_edge(int u,int v,int w){
32     e[tot].to=v;
33     e[tot].w=w;
34     e[tot].nxt=head[u];
35     head[u]=tot++;
36 }
37
38 void dfs(int u,int fa,int dep){
39     ver[++id]=u;//第i个访问到的结点编号
40     depth[id]=dep;//第i个访问到的结点深度
41     first[u]=id;
42     for(int i=head[u];i!=-1;i=e[i].nxt){
43         int v=e[i].to;
44         int w=e[i].w;
45         if(v==fa) continue;
46         dis[v]=dis[u]+w;//dis是先序遍历求
47         dfs(v,u,dep+1);
48         ver[++id]=u;//后序遍历,再次访问父节点
49         depth[id]=dep;
50     }
51 }
52
53 void rmq_init(int n){
54     int k=int(log(n)/log(2));
55     for(int i=1;i<=n;i++)    rmq[i][0]=i;
56     for(int j=1;j<=k;j++){
57         for(int i=1;i+_pow[j]-1<=n;i++){//因为存的是索引
58             int a=rmq[i][j-1],b=rmq[i+_pow[j-1]][j-1];
59             if(depth[a]<depth[b])    rmq[i][j]=a;
60             else  rmq[i][j]=b;
61         }
62     }
63 }
64
65 int rmq_query(int l,int r){
66     int k=int(log(r-l+1)/log(2));
67     int a=rmq[l][k],b=rmq[r-_pow[k]+1][k];
68     if(depth[a]<depth[b])  return a;
69     else  return b;
70 }//返回的依然是索引
71
72 int LCA(int u,int v){
73     int x=first[u],y=first[v];
74     if(x>y)swap(x,y);
75     int res=rmq_query(x,y);
76     return ver[res];
77 }
78
79 int main(){
80     for(int i=0;i<maxn;i++)    _pow[i]=1<<i; //预处理2^n
81     int t,a,b,c;
82     t=read();
83     while(t--){
84         init();
85         n=read();m=read();
86         for(int i=0;i<n-1;i++) a=read(),b=read(),c=read(),add_edge(a,b,c),add_edge(b,a,c);
87         dfs(1,-1,0);
88         rmq_init(2*n-1);
89         for(int i=0;i<m;i++){
90             a=read(),b=read();
91             int ans=LCA(a,b);
92             printf("%d\n",dis[a]+dis[b]-2*dis[ans]);
93         }
94     }
95     return 0;
96 }
时间: 2024-08-10 01:04:45

[hdu2586]How far away?(LCA)的相关文章

hdu2586 LCA

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 思路:在求解最近公共祖先的问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好的处理技巧就是在回溯到结点u的时候,u的子树已经遍历, 这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是 u的父亲结点.以此类推.这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合

hdu-2586 How far away ?(lca+bfs+dfs+线段树)

题目链接: How far away ? Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this

hdu2586(LCA模板)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 还是要多练习,不够熟练.. 可以一看:http://blog.csdn.net/nameofcsdn/article/details/52230548 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6

HDU2586 How far away ?(LCA模板题)

题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:具体讲解 传送门 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 40010; struc

HDU2586.How far away ?-LCA(在线ST算法)

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

hdu2586 /// tarjan离线求树上两点的LCA

题目大意: 询问一棵树里 u 到 v 的距离 可由 dis[ u到根 ] + dis[ v到根 ] - 2*dis[ lca(u,v) ] 得到 https://blog.csdn.net/csyzcyj/article/details/10051173 #include <bits/stdc++.h> #define mem(i,j) memset(i,j,sizeof(i)) using namespace std; const int N=40005, Q=205; struct EDG

POJ-1330&amp;HDU-2586 最近公共祖先(不带权+带权)树剖式写法求LCA

其实敲树剖敲多了就会手敲,然后就发现其实树剖也是可以求LCA的,根据树剖的经验,我们两遍dfs后关于询问l,r的情况我们就开始跳链,当l,r处于同一个链的时候返回深度较小的那个点就好了,这里给个例题: 题目链接:http://poj.org/problem?id=1330 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown

lca最短公共祖先模板(hdu2586)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 #include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<vector> #include<string.h> #include<cstring> #include<algorithm> #include<s

最近公共祖先 LCA Tarjan算法

来自:http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html 对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个点所有的祖先结点中深度最大的一个结点. 0 | 1 /   \ 2      3 比如说在这里,如果0为根的话,那么1是2和3的父亲结点,0是1的父亲结点,0和1都是2和3的公共祖先结点,但是1才是最近的公共祖先结点,或者说1是2和3的所有祖先结点中距离根结点最远的祖先结点. 在求解最近公共祖先为问