题目链接

Description

Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible!

Input

  • Lines 1..1+M: Same format as "Navigation Nightmare"

  • Line 2+M: A single integer, K. 1 <= K <= 10,000

  • Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.

Output

  • Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.

Sample Input

7 6

1 6 13 E

6 3 9 E

3 5 7 S

4 1 3 N

2 4 20 W

4 7 2 S

3

1 6

1 4

2 6

Sample Output

13

3

36

Hint

Farms 2 and 6 are 20+3+13=36 apart.

分析:

要求的是任意两个农场之间的距离,题目上虽然给出了路的方向,但是这对于解题来说没有影响,可以看作无向图。并且两个节点之间至多有1条路,根据数据建图一定是一颗树。所以我们可以先把任一节点作为根节点,用深搜获取每个节点到根节点的距离,然后用Tarjan算法求最近公共祖先以及两点间的距离。

具体实现时深搜求距离和Tarjan算法求最近公共祖先可以同时进行,由于储存点的时候既要方便遍历与某节点相邻的所有节点,又要存储边权,同时最好能直接通过下标来访问数据。一般的结构体或者vector数组就不好用了。这里采用了“前向星”的数据结构。

Tarjan算法:

对于新搜索到的一个节点,首先创建由这个节点构成的集合,再对当前结点的每个子树进行搜索,每搜索完一棵子树,则可以确定子树内的LCA询问都已解决。其他的LCA询问的结果必然在这个子树之外,这时把子树所形成的集合与前节点的集合合并,并将当前节点设为这个集合的祖先。之后继续索搜下一刻子树,直到当前节点的所有子树搜索完毕。这时把当前节点也设为已被检查过的,同时可以处理有关当前节点的lCA询问,如果有一个从当前节点到节点v的询问,且v已被检查过,则由于进行的是深度优先搜索,当前节点与v的最近公共祖先一定还没有检查,而这个最近公共祖先的包含v的子树一定搜索过了,那么这个最近公共祖先一定是v所在集合的祖先。

即对于每个节点u:

1.建立以u为代表元素的集合

2.遍历与u相连的节点v,如果没有被访问过,对于v使用Tarjan算法,结束后,将v的集合并入u的集合。

3.对于与u有关的询问(u,v),如果v被访问过,则结果就是v所在集合的代表元素。

递归求节点i到根节点的距离时,公式为:节点i对应起点到根节点的距离 + 起点到i的距离。对于所要求的两点间的距离公式为:两点到根节点的距离和 - 2 * 两点的最近公共祖先到根节点的距离。

代码:

#include<stdio.h>
#include<string.h>
#define MAX 80005 int id,iq; //分别记录存储的点和询问的个数
int f[MAX],vis[MAX],dis[MAX]; //dis[i]记录根节点到i的距离
//head[i]记录以i为起点的第一条边的下标,qhead类似
int head[MAX],qhead[MAX]; struct node
{ //前向星
int w; //两点间权值
int to; //终点
int next; //和to起点相同的下一条边的存储下标
} edge[MAX],que[MAX]; void add_edge(int u,int v,int w)
{ //加点
edge[id].to=v;
edge[id].w=w;
edge[id].next=head[u];
head[u]=id++;
edge[id].to=u;
edge[id].w=w;
edge[id].next=head[v];
head[v]=id++;
} void add_que(int u,int v)
{ //加询问
que[iq].to=v;
que[iq].next=qhead[u];
qhead[u]=iq++;
que[iq].to=u;
que[iq].next=qhead[v];
qhead[v]=iq++;
} void init(int n)
{ //并查集的初始化函数
int i;
for(i=0;i<=n;i++) f[i]=i;
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
memset(head,-1,sizeof(head)); //head初始化为-1,表示无下一条边
memset(qhead,-1,sizeof(qhead));
} int find(int x)
{ //并查集的压缩路径版查找函数
if(x!=f[x]) f[x]=find(f[x]);
return f[x];
} void Tarjan(int root)
{
int i;
vis[root]=1;
f[root]=root;
for(i=head[root];i!=-1;i=edge[i].next)
{ //不断搜索以当前顶点为起点的节点
if(!vis[edge[i].to])
{
//根节点到终点的距离=根节点到起点的距离 + 边权
dis[edge[i].to]=dis[root]+edge[i].w;
Tarjan(edge[i].to);
f[edge[i].to]=root;
}
}
for(i=qhead[root];i!=-1;i=que[i].next)
{ //查询和当前节点有关的询问
if(vis[que[i].to])
{
//两点间距离为两点到根节点的距离和 - 两倍的最近总共祖先到根节点距离
que[i].w=dis[root]+dis[que[i].to]-2*dis[find(que[i].to)];
que[i^1].w=que[i].w; //第i和i+1的结果相同(i为偶数)
}
}
} int main()
{
int i,t,n,m,k,u,v,w;
scanf("%d%d",&n,&m); //顶点数和边数
init(n);
id=0;
for(i=0;i<m;i++)
{
scanf("%d%d%d%*c%*c",&u,&v,&w); //两节点及其之间的权值
add_edge(u,v,w);
}
scanf("%d",&k); //询问数
iq=0;
for(i=0;i<k;i++)
{
scanf("%d%d",&u,&v);
add_que(u,v);
}
Tarjan(1); //选节点1作为根节点
for(i=0;i<iq;i+=2) printf("%d\n",que[i].w);
return 0;
}

POJ 1986 Distance Queries (Tarjan算法求最近公共祖先)的更多相关文章

  1. tarjan算法求最近公共祖先

    tarjian算法 LCA: LCA(Least Common Ancestor),顾名思义,是指在一棵树中,距离两个点最近的两者的公共节点.也就是说,在两个点通往根的道路上,肯定会有公共的节点,我们 ...

  2. POJ 1986 Distance Queries / UESTC 256 Distance Queries / CJOJ 1129 【USACO】距离咨询(最近公共祖先)

    POJ 1986 Distance Queries / UESTC 256 Distance Queries / CJOJ 1129 [USACO]距离咨询(最近公共祖先) Description F ...

  3. POJ.1986 Distance Queries ( LCA 倍增 )

    POJ.1986 Distance Queries ( LCA 倍增 ) 题意分析 给出一个N个点,M条边的信息(u,v,w),表示树上u-v有一条边,边权为w,接下来有k个询问,每个询问为(a,b) ...

  4. POJ 1986 Distance Queries LCA两点距离树

    标题来源:POJ 1986 Distance Queries 意甲冠军:给你一棵树 q第二次查询 每次你问两个点之间的距离 思路:对于2点 u v dis(u,v) = dis(root,u) + d ...

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

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

  6. POJ 1986 Distance Queries (最近公共祖先,tarjan)

    本题目输入格式同1984,这里的数据范围坑死我了!!!1984上的题目说边数m的范围40000,因为双向边,我开了80000+的大小,却RE.后来果断尝试下开了400000的大小,AC.题意:给出n个 ...

  7. POJ 1986 Distance Queries(Tarjan离线法求LCA)

    Distance Queries Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 12846   Accepted: 4552 ...

  8. POJ - 1986 Distance Queries(离线Tarjan算法)

    1.一颗树中,给出a,b,求最近的距离.(我没考虑不联通的情况,即不是一颗树的情况) 2.用最近公共祖先来求, 记下根结点到任意一点的距离dis[],这样ans = dis[u] + dis[v] - ...

  9. POJ 1986 - Distance Queries - [LCA模板题][Tarjan-LCA算法]

    题目链接:http://poj.org/problem?id=1986 Description Farmer John's cows refused to run in his marathon si ...

随机推荐

  1. node入门学习(一)

    一.安装node.js 方式很多npm,git等,新手建议从官网上直接去下载node的安装包.一键安装. 二.创建一个web服务器. const http = require('http'); htt ...

  2. redis批量删除key 命令

    redis-cli -n 数据库编号 -a 密码 keys "过滤条件" | xargs redis-cli -n 数据库编号 -a 密码 del Demo: redis-cli ...

  3. php反射方法信息

    <?phpclass ReflectionFunction implements Reflector{    final private __clone()    public object _ ...

  4. php手册 | python手册 | perl手册 | c#.net手册 | c++手册 | ruby手册 | jquery手册 | js手册 | prototype手册 | mysql手册 | smarty手册 | css手册 | html手册 | nginx手册 | apache手册 | shell手册 | svn手册

    收集各种实用类手册: http://shouce.jb51.net/shell/

  5. File FileStream StreamReader StreamWriter C#

    存在各种各样的IO设备,比如说文件File类(字符串文件和二进制文件),可以直接使用File类对文件进行读写操作. 这些各种IO的读取和写入是通过流的形式实现的,基类为Stream,针对各种不同的IO ...

  6. JVM学习笔记(一):Java内存区域

    由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分.在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程: 首先Java源代码文件(. ...

  7. C++模式学习------原型模式

    原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.意思就是从A的实例得到一份与A内容相同,但是又互不干扰的实例B. class base { public : base(co ...

  8. widows终端远程连接Linux服务器

    一.前言 为什么不是远程连接Linux服务器? 因为我不会,远程连接window我就用电脑自带的“远程桌面连接”. 以下所述都是在CentOS操作系统下的. 服务器刚换成Linux的时候很迷茫,感觉无 ...

  9. PHP-从零开始使用Solr搜索引擎服务(下)

    前言: 原文地址: http://www.cnblogs.com/JimmyBright/p/7156085.html 前面在配置完成Solr服务之后,在浏览器上可以打开Solr的管理界面,这个界面几 ...

  10. BZOJ 3165: [Heoi2013]Segment

    3165: [Heoi2013]Segment Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 465  Solved: 187[Submit][Sta ...