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. data-ng-model 指令

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  2. 你不知道的javaScript笔记(1)

    规避冲突 function foo(){ function bar(a){ i = 3; console.log(a + i); } for ( var i=0; i < 10; i++){ b ...

  3. ABAP术语-Lock Argument

    Lock Argument 原文:http://www.cnblogs.com/qiangsheng/archive/2008/02/29/1085717.html Locked fields in ...

  4. WIN10 vagrant和virtualbox虚拟机和一键搭建lnmp环境配置thinkphp虚拟主机

    版本:win10系统 virtualbox:5.1.26 vagrant :1.9.7 centos 7.0 xshell/git 首先下载好对应版本的软件 配置vagrant和virtualbox ...

  5. 微信小程序navigator无法跳转情况

    情况有三种 跳转的页面没有在app.json中注册 跳转的路径不正确 以上两种在命令行(console)中都会提示 跳转的页面在TabBar中,需要将open-type属性是设置为switchTab

  6. 【解决】MongoDB 线上业务处理,数据去重脚本实现

    mongo客户端工具下载  https://robomongo.org/download   线上业务,k线 展示出现问题,相同时间戳的数据多次插入导致数据不真实,后经排查发现是每次都是写的四条数据, ...

  7. Ajax在表单中的应用

    ajax在注册用户表单中的使用 1.验证用户名是否被使用 2.获取手机短信验证码 3.点击表单中的图片刷新,可实现刷新图片验证码 <!DOCTYPE html> <html> ...

  8. Python核心框架tornado的异步协程的2种方式

    什么是异步? 含义 :双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位 现象:没有共同的时钟,不考虑顺序来了 ...

  9. git merge最简洁

    一.开发分支(dev)上的代码达到上线的标准后,要合并到 master 分支 git checkout devgit pullgit checkout mastergit merge devgit p ...

  10. SVN配置自启动-1053错误

    主要内容:解决启动“配置的svn自启动服务”报1053错误 1. 环境: 系统: wind10 svn服务端版本: VisualSVN-Server-3.8.0-x64 2. 配置自启动 以管理员身份 ...