博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu 2586 How far away ? (LCA)
阅读量:5766 次
发布时间:2019-06-18

本文共 4406 字,大约阅读时间需要 14 分钟。

How far away ?

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4244    Accepted Submission(s): 1617

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"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
 

 

Input
First line is a single integer T(T<=10), indicating the number of test cases.
  For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
  Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
 

 

Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
 

 

Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
 
 
2 2
1 2 100
1 2
2 1
 

 

Sample Output
10
25
100
100
 

 

Source
 

 

Recommend
lcy   |   We have carefully selected several similar problems for you:            
 

 参考: 

这篇博客写的非常不错,我就是看这个学会的。

第一次写最近公共祖先问题,用的邻接表指针。

对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个点所有的祖先结点中深度最大的一个结点。

       0

       |

       1

     /   \

   2      3

比如说在这里,如果0为根的话,那么1是2和3的父亲结点,0是1的父亲结点,0和1都是2和3的公共祖先结点,但是1才是最近的公共祖先结点,或者说1是2和3的所有祖先结点中距离根结点最远的祖先结点。

在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好的处理技巧就是在回溯到结点u的时候,u的子树已经遍历,这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是u的父亲结点。以此类推。。这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合中的所属不同集合的任意一对顶点的公共祖先都是相同的,也就是说这两个集合的最近公共最先只有一个。对于每个集合而言可以用并查集来优化,时间复杂度就大大降低了,为O(n + q),n为总结点数,q为询问结点对数。

 

 

算法名称

针对问题

时间消耗

空间消耗

ST算法

一般RMQ问题

O(Nlog2N)-O(1)

O(Nlog2N)

Tarjan算法

LCA问题

O(Na(N) + Q)

O(N)

±1RMQ算法

±1RMQ问题

O(N)-O(1)

O(N)

不懂算法的可以找棵树模拟一下递归的过程。

给出Tarjan离线算法的做法:

1 //62MS    4232K    1750 B    G++ 2 /* 3  4     第一题LCA: 5         在看完算法后发现还未能完全实现,因为理解还不透彻,所以想先做 6     一题然后再从题入手。看了别人的结题报告后才写的,感觉还好。 7     这一题就是模板题了。这里采用的是离线算法Tarjan。  8       9      树两点的间的最近距离=根节点分别到两点间的最近距离-2*根节点到两点的LCA距离。 10          11          ans = dis[u] + dis[v] - 2 * dis[lca(v, v)] 12 13 */14 #include
15 #include
16 #include
17 #define N 4000518 using namespace std;19 struct node{20 int v;21 int d;22 node(int a,int b){23 v=a;d=b;24 }25 };26 vector
child[N],V[N]; //分别记录树和询问的邻接表 27 int set[N]; 28 int vis[N];29 int dis[N];30 int res[205][3]; //res[i][0]=u;res[i][1]=v;res[i][2]=LCA(u,v); 31 int n;32 void init()33 {34 for(int i=0;i<=n;i++){ 35 child[i].clear();36 V[i].clear();37 }38 memset(vis,0,sizeof(vis));39 memset(dis,0,sizeof(dis));40 memset(res,0,sizeof(res));41 }42 int find(int x)43 {44 if(set[x]!=x) set[x]=find(set[x]);45 return set[x];46 }47 void merge(int x,int y)48 {49 int x0=find(x);50 int y0=find(y);51 set[y0]=x0;52 } 53 void LCA(int u) //tarjan算法 54 {55 set[u]=u;56 vis[u]=true;57 for(int i=0;i
View Code

 

 再给出基于RMQ在线算法的做法:

1 //78MS    13100K    1892 B    G++ 2 #include
3 #include
4 #include
5 #define N 40005 6 struct node{ 7 int u,v,d; 8 int next; 9 }edge[2*N]; //邻接表 10 int tot,head[N]; //记录先序遍历出现次序,邻接表头 11 int set[2*N],first[N]; //记录父节点与次序数 12 int dep[2*N],dis[N]; //记录深度和距离 13 int dp[2*N][30];14 bool vis[N];15 void addedge(int u,int v,int d,int &k) //加边 16 {17 edge[k].u=u;18 edge[k].v=v;19 edge[k].d=d;20 edge[k].next=head[u];21 head[u]=k++;22 }23 int Min(int a,int b) //比较的是深度 24 {25 return dep[a]
y){61 int temp=x;x=y;y=temp;62 }63 return set[RMQ(x,y)];64 }65 int main(void)66 {67 int t,n,q;68 scanf("%d",&t);69 while(t--)70 {71 int u,v,d;72 int num=0;73 scanf("%d%d",&n,&q);74 memset(head,-1,sizeof(head));75 memset(vis,false,sizeof(vis));76 for(int i=1;i
View Code

 

 

转载于:https://www.cnblogs.com/GO-NO-1/p/3661949.html

你可能感兴趣的文章
【SDN】Openflow协议中对LLDP算法的理解--如何判断非OF区域的存在
查看>>
纯DIV+CSS简单实现Tab选项卡左右切换效果
查看>>
redis 常用命令
查看>>
EdbMails Convert EDB to PST
查看>>
android 资源种类及使用
查看>>
Centos7同时运行多个Tomcat
查看>>
使用CocoaPods过程中的几个问题
查看>>
我的友情链接
查看>>
为eclipse安装maven插件
查看>>
JAVA8 Stream 浅析
查看>>
inner join on, left join on, right join on要详细点的介绍
查看>>
SAS vs SSD对比测试MySQL tpch性能
查看>>
Spring boot 整合CXF webservice 全部被拦截的问题
查看>>
Pinpoint跨节点统计失败
查看>>
【Canal源码分析】Canal Server的启动和停止过程
查看>>
机房带宽暴涨问题分析及解决方法
查看>>
XP 安装ORACLE
查看>>
八、 vSphere 6.7 U1(八):分布式交换机配置(vMotion迁移网段)
查看>>
[转载] 中华典故故事(孙刚)——19 万岁
查看>>
php5编译安装常见错误和解决办法集锦
查看>>