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. Oracle listener.log 清理

    在oracle中,如果不对监听日志文件进行截断(定期清理),那么监听日志文件会变得越来越大,由于一些老旧的OS不支持2GB以上的文件,故当listener.log文件超过2GB时,会出现无法处理新的连 ...

  2. js关于if(''==0)

    在js当中,如下注意 if(''==0){ alert("空字符代表false"); } 空字符串代表false 0代表false false==false 结果就为true了

  3. 【PTA 天梯赛】L2-016. 愿天下有情人都是失散多年的兄妹(深搜)

    呵呵.大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人.父母.祖父母.曾祖父母.高祖父母)则不可通婚.本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚? 输入格式: 输入 ...

  4. 小胖办证 wzoi

    小胖办证 题目描述: xuzhenyi要办个签证.办证处是一座M层的大楼,1<=M<=100. 每层楼都有N个办公室,编号为1..N(1<=N<=500).每个办公室有一个签证 ...

  5. poj 2553 The Bottom of a Graph : tarjan O(n) 存环中的点

    /** problem: http://poj.org/problem?id=2553 将所有出度为0环中的点排序输出即可. **/ #include<stdio.h> #include& ...

  6. round函数在oracle和mysql中用法

    1.oracle和mysql通用方法 #round(字段1,小数位数) 四舍五入select round('11.123456',4);结果:11.1235 2.mysql的另外2种保留小数位数方法# ...

  7. windows下上传shell脚本不能运行—将dos模式修改为unix 文件格式

    windows下上传shell脚本至linux,其格式将为dos.dos模式的shell脚本将不能再linux下正确运行,需要修改文件模式为unix. 1 查看文件模式方法 linux服务器上,用vi ...

  8. Java OOP——第二章 继承

    1. 继承: ●继承是面向对象的三大特征之一,是JAVA实现代码重用的重要手段之一: ●继承是代码重用的一种方式,将子类共有的属性和行为放到父类中: ●JAVA只支持单继承,即每一个类只有一个父类,继 ...

  9. Java OOP——第四章 异常

    1. 接口:接口就是给出一些没有内容的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来. 接口是更加抽象的抽象的类, 抽象类里的方法可以有方法体, 接口里的所有方法都没有方法体. ...

  10. dom技术解析xml (php)

    1.xml实例 test.xml <?xml version="1.0" encoding="utf-8"?><!DOCTYPE 班级 SYS ...