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

题意:

一个村庄有 n 个房子和 n-1 条双向路,每两个房子之间都有一条简单路径。

如今有m次询问。求两房子之间的距离。

PS:

能够用LCA来解,首先找到u, v 两点的lca,然后计算一下距离值就能够了。

计算方法是。记下根结点到随意一点的距离dis[i],

这样ans = dis[u] + dis[v] - 2 * dis[lca(v, v)]了。

这题要用c++交。G++会爆栈!

代码例如以下:看别人的模板(tarjan 离线)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 40047
#define maxm 247 struct node
{
int to,w,next;
} edge[maxn*2]; int n, m; //点数,询问次数
int head[maxn];
int k;
int fa[maxn]; //父亲结点
int dis[maxn]; //到根节点距离
int vis[maxn]; //是否訪问过
int s[maxm]; //询问起点
int e[maxm]; //询问终点
int lca[maxm]; //LCA(s,e) 近期公共祖先 int find(int x)
{
if(fa[x]!=x) return fa[x]=find(fa[x]);
return fa[x];
} void init()
{
k = 1;
memset(head,0,sizeof(head));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
} void add(int u,int v,int w)
{
edge[k].to = v;
edge[k].w = w;
edge[k].next = head[u];
head[u] = k++;
} void tarjan(int u)
{
int i,v;
fa[u] = u;
vis[u] = 1;
for(i = 0; i < m; i++)
{
if(e[i]==u && vis[s[i]])
lca[i] = find(s[i]); //若询问的两点中有一点已被訪问过。则两点的LCA则为这一点的当前父节点
if(s[i]==u && vis[e[i]])
lca[i] = find(e[i]);
}
for(i = head[u]; i; i = edge[i].next)
{
v = edge[i].to;
if(!vis[v]) //若没被訪问过
{
dis[v] = dis[u]+edge[i].w;//更新距离
tarjan(v);
fa[v] = u;//回溯更新父节点
}
}
} int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
int u, v, w;
for(int i = 0; i < n-1; i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(int i = 0; i < m; i++)
{
scanf("%d%d",&s[i],&e[i]);
}
tarjan(1); for(int i = 0; i < m; i++)
{
printf("%d\n",dis[s[i]]+dis[e[i]]-2*dis[lca[i]]);//两点距离为根节点到两点距离之和-根节点到LCA距离*2
}
}
return 0;
}

(ST在线算法 转)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000") //不须要申请系统栈
const int N = 40010;
const int M = 25;
int dp[2*N][M]; //这个数组记得开到2*N,由于遍历后序列长度为2*n-1
bool vis[N];
struct edge
{
int u,v,w,next;
} e[2*N];
int tot,head[N];
inline void add(int u ,int v ,int w ,int &k)
{
e[k].u = u;
e[k].v = v;
e[k].w = w;
e[k].next = head[u];
head[u] = k++;
u = u^v;
v = u^v;
u = u^v;
e[k].u = u;
e[k].v = v;
e[k].w = w;
e[k].next = head[u];
head[u] = k++;
}
int ver[2*N],R[2*N],first[N],dir[N];
//ver:节点编号 R:深度 first:点编号位置 dir:距离
void dfs(int u ,int dep)
{
vis[u] = true;
ver[++tot] = u;
first[u] = tot;
R[tot] = dep;
for(int k=head[u]; k!=-1; k=e[k].next)
if( !vis[e[k].v] )
{
int v = e[k].v , w = e[k].w;
dir[v] = dir[u] + w;
dfs(v,dep+1);
ver[++tot] = u;
R[tot] = dep;
}
}
void ST(int n)
{
for(int i=1; i<=n; i++)
dp[i][0] = i;
for(int j=1; (1<<j)<=n; j++)
{
for(int i=1; i+(1<<j)-1<=n; i++)
{
int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
dp[i][j] = R[a]<R[b]?a:b;
}
}
}
//中间部分是交叉的。
int RMQ(int l,int r)
{
int k=0;
while((1<<(k+1))<=r-l+1)
k++;
int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号
return R[a]<R[b]?a:b;
} int LCA(int u ,int v)
{
int x = first[u] , y = first[v];
if(x > y) swap(x,y);
int res = RMQ(x,y);
return ver[res];
} int main()
{
//freopen("Input.txt","r",stdin);
//freopen("Out.txt","w",stdout);
int cas;
scanf("%d",&cas);
while(cas--)
{
int n,q,num = 0;
scanf("%d%d",&n,&q);
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
for(int i=1; i<n; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,num);
}
tot = 0;
dir[1] = 0;
dfs(1,1);
/*printf("节点ver "); for(int i=1; i<=2*n-1; i++) printf("%d ",ver[i]); cout << endl;
printf("深度R "); for(int i=1; i<=2*n-1; i++) printf("%d ",R[i]); cout << endl;
printf("首位first "); for(int i=1; i<=n; i++) printf("%d ",first[i]); cout << endl;
printf("距离dir "); for(int i=1; i<=n; i++) printf("%d ",dir[i]); cout << endl;*/
ST(2*n-1);
while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
int lca = LCA(u,v);
printf("%d\n",dir[u] + dir[v] - 2*dir[lca]);
}
}
return 0;
}

HDU 2586 How far away ?(LCA模板 近期公共祖先啊)的更多相关文章

  1. LCA模板 ( 最近公共祖先 )

    LCA 有几种经典的求取方法.这里只给出模板,至于原理我完全不懂. 1.RMQ转LCA.复杂度O(n+nlog2n+m) 大致就是 DFS求出欧拉序 => 对欧拉序做ST表 => LCA( ...

  2. UVA - 11354Bond最小生成树,LCA寻找近期公共祖先

    看懂题目意思.他的意思是求将全部的城市走一遍,危急度最小.而且给 你两个s,t后让你求在走的时候,从s到t过程中危急度最大的值,并输出它, 然后就是怎样攻克了,这个题目能够说简单,也能够说难 通过思考 ...

  3. LintCode 近期公共祖先

    中等 近期公共祖先 查看执行结果 34% 通过 给定一棵二叉树,找到两个节点的近期公共父节点(LCA). 近期公共祖先是两个节点的公共的祖先节点且具有最大深度. 您在真实的面试中是否遇到过这个题? Y ...

  4. 连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(近期公共祖先)

    PS:摘自一不知名的来自大神. 1.割点:若删掉某点后.原连通图分裂为多个子图.则称该点为割点. 2.割点集合:在一个无向连通图中,假设有一个顶点集合,删除这个顶点集合,以及这个集合中全部顶点相关联的 ...

  5. LCA近期公共祖先

    LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...

  6. POJ 1470 Closest Common Ancestors【近期公共祖先LCA】

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/35311489 题目链接:http://poj ...

  7. 近期公共祖先(LCA)——离线Tarjan算法+并查集优化

    一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...

  8. LCA 近期公共祖先 小结

    LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...

  9. POJ1330Nearest Common Ancestors——近期公共祖先(离线Tarjan)

    http://poj.org/problem? id=1330 给一个有根树,一个查询节点(u,v)的近期公共祖先 836K 16MS #include<iostream> #includ ...

随机推荐

  1. flume+flume+kafka消息传递+storm消费

    通过flume收集其他机器上flume的监测数据,发送到本机的kafka进行消费. 环境:slave中安装flume,master中安装flume+kafka(这里用两台虚拟机,也可以用三台以上) m ...

  2. Java并发基础知识点详解

    1.synchronized与Lock区别 父类有synchtonized,子类调用父类的同步方法,是没办法同步的,因为synchronized不是修饰符,不会被继承下来. synchronized ...

  3. android 提纲挈领

    之后的android学习将侧重三方面: 1.基础内容例如xml属性.sharedpreference.数据库必须能够熟记于心. 2.开源library熟练应用,能够了解如何更好地使用各种开源libra ...

  4. IDEA 使用 git (码市)

    1.下载 git,并安装(一直下一步) 2.使用IDEA,检出项目,检出方式选择:git, 3.如果项目有修改,上传修改的文件 4.下载 SourceTree(git的图形化工具),并安装(一直下一步 ...

  5. 7.union

    联合结果集union 简单的结果集联合: select number,name,age from emp union select cardnumber,name,age from emp2 基本的原 ...

  6. 【转载】排名Top 16的Java实用类库

    *转载自HollisChuang 链接:http://www.hollischuang.com/archives/1606 1. org.apache.commons.io.IOUtils close ...

  7. 前端-Vue学习思维导图笔记

    看不清的朋友右键保存或者新窗口打开哦!喜欢我可以关注我,还有更多前端思维导图笔记有vue结构分析,JS基础,JQ,JS高级,Angular,git等等

  8. oracle 命令记录

    监听程序启动停止查看名利: 1.切换到oracle用户:su - oracle 2.查看监听状态:lsnrctl status 3.停止监听:lsnrctl stop 4.启动监听:lsnrctl s ...

  9. jQuery顺序加载图片(初版)

    浏览器加载图片区别: IE:同时加载与渲染 其他:加载完之后再渲染 根据这个差异用jQuery做个实例:按顺序加载一组图片,加载完成后提示. <!DOCTYPE html> <htm ...

  10. cmd 运行 svn 亲测!!!

    如果之前安装了svn客户端,但是一直提示svn停止工作的话就可以用cmd去操作svn更新和提交了:或者可以直接用别的代码IDE(包含svn插件的)去进行svn的操作. 接下来我说说windows如何用 ...