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. block与inline,inline和inline-block,块级和行内元素,行内替换和行内非替换元素

    block:块级元素默认display属性为block:无论块内内容有多少,总是占满一行: inline:行内元素默认display属性为inline:只占据块内的内容的大小,不会占满一整行: inl ...

  2. 数据恢复顾问(DRA)

    (1)DRA介绍 数据恢复顾问(Data Recovery Advise)是一个诊断和修复数据库的工具,DRA能够修复数据文件和(某些环境下)控制文件的损坏,它不提供spfile和logfile的修复 ...

  3. HTML中footer固定在页面底部的若干种方法

    <div class="header"><div class="main"></div></div> <d ...

  4. java程序执行命令行,解锁数据库表

    有些表锁的时间长或其他原因,在plsql中不能解锁,只能用命令行解锁. 有些功能跨平台系统的交互偶尔会锁表,就需要自动解锁. 下面是解锁的代码: package com.lg.BreakOracleU ...

  5. pywinauto 使用

    Pywinauto是基于Python开发的,用于自动化测试的脚本模块,主要操作于Windows标准图形界面.它可以允许你很容易的发送鼠标.键盘动作给Windows的对话框和控件.  其中,最主要功能为 ...

  6. wamp2.5怎么设置虚拟域名

    换了台电脑~好不顺手.老大的机器上装的是wamp.几年没用差点连怎么设置虚拟域名都忘记了.自己写点东西~做个备忘吧. 首先,版本 然后在网上百度一堆七七八八的.做的时候没那么复杂.跟phpstudy差 ...

  7. doc命令操作数据库(下)

    1.给数据表添加一组数据: 2.给数据表添加多组数据: 3.对数据进行删除和修改: 4.用select查询单个或多个数据信息: 5.去除重复值: 6.查询的各种用法: between的用法: 查询排序 ...

  8. JavaSE 第二次学习随笔(四)

    ---------------------------------------------------------------------------------------------------- ...

  9. Python学习手册之控制结构(一)

    在上一篇文章中,我们对 Python 进行了简单介绍和介绍了 Python 的基本语法,现在我们继续介绍 Python 控制结构. 查看上一篇文章请点击:https://www.cnblogs.com ...

  10. 阿里云异常网络连接-可疑WebShell通信行为的分析解决办法

    2018年10月27日接到新客户网站服务器被上传了webshell脚本木马后门问题的求助,对此我们sine安全公司针对此阿里云提示的安全问题进行了详细分析,ECS服务器被阿里云提示异常网络连接-可疑W ...