The traffic network in a country consists of N cities (labeled with integers from 1 to N) and N-1 roads connecting

the cities. There is a unique path between each pair of different cities, and we know the exact length of each road.

Write a program that will, for each of the K given pairs of cities, find the length of the shortest and the length

of the longest road on the path between the two cities.

Input

The first line of input contains an integer N, 2 ≤ N ≤ 100 000. Each of the following N-1 lines contains three

integers A, B and C meaning that there is a road of length C between city A and city B. 
The length of each road will be a positive integer less than or equal to 1 000 000. 
The next line contains an integer K, 1 ≤ K ≤ 100 000. Each of the following K lines contains two different

integers D and E – the labels of the two cities constituting one query.

Output

Each of the K lines of output should contain two integers – the lengths from the task description for the

corresponding pair of the cities.

题目大意:给一棵n个点的树,每条边有一个权值,k个询问,问u到v的简单路径中,权值最小和最大分别为多少。

思路:首先要会普通的tarjan求LCA的算法,在合并集合的时候算出每个点到其根节点的最小和最大权值,在求出某一对询问(u, v)的LCA之后,回溯到他们的LCA的时候把LCA的子集都合并到了LCA上,那么u和v分别到LCA的最小最大权值就知道了,再取其中的最小最大值即可。

PS:时间复杂度为O(n+k)

代码(6470MS):

 #include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define X first
#define Y second
typedef pair<int, int> PII;
typedef vector<PII> VPII;
typedef vector<int> VI; const int MAXN = ;
const int MAXE = MAXN << ;
const int INF = 0x7fff7fff; int head[MAXN], to[MAXE], next[MAXE], cost[MAXE], ecnt;
int n, m, fa[MAXN]; PII edge[MAXN], a[MAXN], ans[MAXN];
VPII query[MAXN];
VI b[MAXN]; bool vis[MAXN]; void init() {
for(int i = ; i <= n; ++i) fa[i] = i;
ecnt = ;
} void add_edge(int u, int v, int w) {
to[ecnt] = v; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; cost[ecnt] = w; next[ecnt] = head[v]; head[v] = ecnt++;
} int get_set(int x) {
if(fa[x] == x) return x;
int ret = get_set(fa[x]);
edge[x].X = max(edge[x].X, edge[fa[x]].X);
edge[x].Y = min(edge[x].Y, edge[fa[x]].Y);
return fa[x] = ret;
} void LCA(int u, int f) {
edge[u].X = ; edge[u].Y = INF;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(v == f) continue;
LCA(v, u);
edge[v].X = edge[v].Y = cost[p];
fa[v] = u;
}
vis[u] = true;
for(VPII::iterator it = query[u].begin(); it != query[u].end(); ++it)
if(vis[it->X]) b[get_set(it->X)].push_back(it->Y);
for(VI::iterator it = b[u].begin(); it != b[u].end(); ++it) {
int id = *it, u = a[id].X, v = a[id].Y;
get_set(u); get_set(v);
ans[id] = make_pair(max(edge[u].X, edge[v].X), min(edge[u].Y, edge[v].Y));
}
} int main() {
scanf("%d", &n);
init();
for(int i = ; i < n; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
}
scanf("%d", &m);
for(int i = ; i <= m; ++i) {
scanf("%d%d", &a[i].X, &a[i].Y);
query[a[i].X].push_back(make_pair(a[i].Y, i));
query[a[i].Y].push_back(make_pair(a[i].X, i));
}
LCA(, );
for(int i = ; i <= m; ++i) printf("%d %d\n", ans[i].Y, ans[i].X);
}

SPOJ 3978 Distance Query(tarjan求LCA)的更多相关文章

  1. 【Tarjan】洛谷P3379 Tarjan求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  2. 倍增\ tarjan求lca

    对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点). dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v ...

  3. Tarjan求LCA

    LCA问题算是一类比较经典的树上的问题 做法比较多样 比如说暴力啊,倍增啊等等 今天在这里给大家讲一下tarjan算法! tarjan求LCA是一种稳定高速的算法 时间复杂度能做到预处理O(n + m ...

  4. 详解使用 Tarjan 求 LCA 问题(图解)

    LCA问题有多种求法,例如倍增,Tarjan. 本篇博文讲解如何使用Tarjan求LCA. 如果你还不知道什么是LCA,没关系,本文会详细解释. 在本文中,因为我懒为方便理解,使用二叉树进行示范. L ...

  5. 倍增 Tarjan 求LCA

                                                                                                         ...

  6. tarjan求lca的神奇

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  7. Tarjan求LCA(离线)

    基本思想 把要求的点对保存下来,在dfs时顺带求出来. 方法 将每个已经遍历的点指向它回溯的最高节点(遍历它的子树时指向自己),每遍历到一个点就处理它存在的询问如果另一个点已经遍历,则lca就是另一个 ...

  8. 图论分支-倍增Tarjan求LCA

    LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...

  9. tarjan求lca :并查集+dfs

    //参考博客 https://www.cnblogs.com/jsawz/p/6723221.html#include<bits/stdc++.h> using namespace std ...

随机推荐

  1. neo4j 安装步骤 转自:http://blog.csdn.net/luoluowushengmimi/article/details/19987995

    1. Neo4j简介 Neo4j是一个用Java实现的.高性能的.NoSQL图形数据库.Neo4j 使用图(graph)相关的概念来描述数据模型,通过图中的节点和节点的关系来建模.Neo4j完全兼容A ...

  2. webpack——概念的引入

    ## 在网页中会引用哪些常见的静态资源?+ JS - .js .jsx .coffee .ts(TypeScript 类 C# 语言)+ CSS - .css .less .sass .scss+ I ...

  3. JS中遍历数组、对象的方式

    1.标准的for循环遍历数组 //不打印自定义属性和继承属性 var array = [1,2,3]; for (var i = 0; i < array.length; i++) { cons ...

  4. oracle查询时间段内的数据

    select * from persons o where trunc(o.create_date) = to_date('2018-07-30','yyyy-mm-dd') minus  对比数据完 ...

  5. Mybatis中使用UpdateProvider注解实现根据主键批量更新

    Mapper中这样写: @UpdateProvider(type = SjjcSqlProvider.class, method = "updateTaskStatusByCBh" ...

  6. C++指针数组,二级指针和函数指针的练习

    1.编一程序,将字符串“Hello,C++!”赋给一个字符数组, 然后从第一个字母开始间隔地输出该串(请用指针完成). 代码如下 #include<iostream> #include&l ...

  7. Linux 内核之api_man 手册安装

    开发环境:Ubuntu18.04,虚拟机virtual box 1.安装XML格式转换 sudo apt  install xmlto 2.在内核目录执行 make mandocs  大概持续了半小时 ...

  8. python-集合类型

    集合具有唯一性(集合中的元素各不相同),无序性,确定性(集合中的元素是不可改变的,不能是列表,字典以及集合本身) 1.add(self, *args, **kwargs),union(self, *a ...

  9. ruby Logger日志

    1.logger创建 # 输出到标准输出 logger = Logger.new(STDERR) logger = Logger.new(STDOUT) # 输出到指定文件 logger = Logg ...

  10. ruby mysql2

    1. mysql2连接选项 Mysql2::Client.new( :host, :username, :password, :port, :database, :socket = '/path/to ...