题目链接: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. Django day13 form组件, 渲染错误信息, 全局钩子

    一:from组件 二:渲染错误信息 三:全局钩子

  2. Tomcat 程序无问题的情况下页面打开变慢的原因

    看看这写日志的频率就知道我有多闲了.. 前言: 其实关于tomcat,遇到过很多关于“慢”的问题,比如启动慢,比如页面打开慢, 以前太忙也太懒,不愿意花时间分析原因,现在终于肯静下来找原因 环境是ec ...

  3. 复习java基础第七天(反射)

    一:目标 Ø理解 Class 类 Ø理解 Java 的类加载机制 Ø学会使用 ClassLoader 进行类加载 Ø理解反射的机制 Ø掌握 Constructor.Method.Field 类的用法 ...

  4. GrepWin:Win7下的文本替换工具

    工作环境退回到Win7之后,内容查找功能非常不给力,推荐一个文本内容查找工具grepWin. Win7下的文本查找/替换工具: grepWin

  5. 【sqli-labs】 less22 Cookie Injection- Error Based- Double Quotes - string (基于错误的双引号字符型Cookie注入)

    注入的过程和less 20 21一样,这次闭合cookie的使用的双引号

  6. C# for 遍历 IPagedList

    IPagedList<Doc> ss = Doclist.ToPagedList(page, pageSize); ;i<ss.Count;i++) { var yy = ss[i] ...

  7. jq遍历table 下的 td 添加类

    <script> $('#btntb').click(function () { $('#tab tr').each(function (i) { // 遍历 tr $(this).chi ...

  8. drf03 drf视图中提供的请求类和响应类

    drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作.所以在django原有的django.views.View类基础上,drf封装了多个子类出来提供给我们使用. Django REST ...

  9. Emoji表情处理工具类

    import java.util.regex.Matcher; import java.util.regex.Pattern; public class EmojiToString { /** * 将 ...

  10. PAT_A1135#Is It A Red-Black Tree

    Source: PAT A1135 Is It A Red-Black Tree (30 分) Description: There is a kind of balanced binary sear ...