zoukankan      html  css  js  c++  java
  • SPOJ 3978 Distance Query(tarjan求LCA)

    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):

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #include <iostream>
     5 #include <algorithm>
     6 #include <vector>
     7 using namespace std;
     8 #define X first
     9 #define Y second
    10 typedef pair<int, int> PII;
    11 typedef vector<PII> VPII;
    12 typedef vector<int> VI;
    13 
    14 const int MAXN = 100010;
    15 const int MAXE = MAXN << 1;
    16 const int INF = 0x7fff7fff;
    17 
    18 int head[MAXN], to[MAXE], next[MAXE], cost[MAXE], ecnt;
    19 int n, m, fa[MAXN];
    20 
    21 PII edge[MAXN], a[MAXN], ans[MAXN];
    22 VPII query[MAXN];
    23 VI b[MAXN];
    24 
    25 bool vis[MAXN];
    26 
    27 void init() {
    28     for(int i = 1; i <= n; ++i) fa[i] = i;
    29     ecnt = 2;
    30 }
    31 
    32 void add_edge(int u, int v, int w) {
    33     to[ecnt] = v; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
    34     to[ecnt] = u; cost[ecnt] = w; next[ecnt] = head[v]; head[v] = ecnt++;
    35 }
    36 
    37 int get_set(int x) {
    38     if(fa[x] == x) return x;
    39     int ret = get_set(fa[x]);
    40     edge[x].X = max(edge[x].X, edge[fa[x]].X);
    41     edge[x].Y = min(edge[x].Y, edge[fa[x]].Y);
    42     return fa[x] = ret;
    43 }
    44 
    45 void LCA(int u, int f) {
    46     edge[u].X = 0; edge[u].Y = INF;
    47     for(int p = head[u]; p; p = next[p]) {
    48         int &v = to[p];
    49         if(v == f) continue;
    50         LCA(v, u);
    51         edge[v].X = edge[v].Y = cost[p];
    52         fa[v] = u;
    53     }
    54     vis[u] = true;
    55     for(VPII::iterator it = query[u].begin(); it != query[u].end(); ++it)
    56         if(vis[it->X]) b[get_set(it->X)].push_back(it->Y);
    57     for(VI::iterator it = b[u].begin(); it != b[u].end(); ++it) {
    58         int id = *it, u = a[id].X, v = a[id].Y;
    59         get_set(u); get_set(v);
    60         ans[id] = make_pair(max(edge[u].X, edge[v].X), min(edge[u].Y, edge[v].Y));
    61     }
    62 }
    63 
    64 int main() {
    65     scanf("%d", &n);
    66     init();
    67     for(int i = 1; i < n; ++i) {
    68         int u, v, w;
    69         scanf("%d%d%d", &u, &v, &w);
    70         add_edge(u, v, w);
    71     }
    72     scanf("%d", &m);
    73     for(int i = 1; i <= m; ++i) {
    74         scanf("%d%d", &a[i].X, &a[i].Y);
    75         query[a[i].X].push_back(make_pair(a[i].Y, i));
    76         query[a[i].Y].push_back(make_pair(a[i].X, i));
    77     }
    78     LCA(1, 0);
    79     for(int i = 1; i <= m; ++i) printf("%d %d
    ", ans[i].Y, ans[i].X);
    80 }
    View Code
  • 相关阅读:
    力扣452题、435题、56题(用最少量的箭引爆气球,无重叠区间,合并区间)
    力扣860题(柠檬水找零)
    力扣135题、406题(分发糖果、根据身高重建队列)
    力扣134题(加油站)
    力扣1005题(K次取反后最大化的数组和)
    力扣122题、714题(买卖股票)
    力扣53题(最大子序和)
    力扣376题(摆动序列)
    力扣455题(分发饼干)
    力扣51题(n皇后)
  • 原文地址:https://www.cnblogs.com/oyking/p/3330897.html
Copyright © 2011-2022 走看看