#USACO 2004 FEB#距离询问(LCA树链问题)

来源:互联网 发布:国外免费网络视频聊天 编辑:程序博客网 时间:2024/05/22 13:20

2684: [USACO 2004 FEB]距离询问

时间限制:1 Sec  内存限制:128 MB

题目描述

FJ有N(2 <= N <= 40,000)个农场,编号从1..N。有M(1 <= M < 40,000)条水平或者垂直的道路连接这些农场(1 <= length <= 1000)。下图是有7个农场的例子,括号中的数字表示道路的长度:
           F1 --- (13) ---- F6 --- (9) ----- F3            |                                 |           (3)                                |            |                                (7)           F4 --- (20) -------- F2            |            |                                 |           (2)                               F5            |            F7 

每个农场最多只与它上、下、左、右的农场相连。任意两个农场之间,只有唯一的一条路径。

现在给出K个询问,形如:X  Y,表示请你回答编号为X的农场与编号为Y的农场之间的路径长度

输入

 第1行:2个整数 N 和 M,意义如前所述

接下来M行,每行4个变量F1, F2, L, D 描述一条道路, F1 和  F2 是这条道路所连接的两个农场的编号, L 是这条道路的长度, D 是这条道路从F1到F2的方向,即 'N', 'E', 'S', 'W' 这4个字母之一,分别表示北,东,南,西

接下来1行上有1个整数K,表示询问的次数K (1 <= K <= 10,000)

接下来K行,每行2个整数X,Y,表示询问X和Y之间的最短距离

输出

 对每个询问,在一个单独的行上,用一个整数回答

样例输入

7 61 6 13 E6 3 9 E3 5 7 S4 1 3 N2 4 20 W4 7 2 S31 61 42 6

样例输出

13336

提示

 Farms 2 and 6 are 20+3+13=36 apart.

学长来讲树链问题,首先是基础的倍增LCA

这题很基础,就是求两个点到它们LCA的距离和,随便提一个当做根,注意首先离线出每个点到Root的距离,然后在线查询(否则就T呐)

Code:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int Maxn = 40000;const int Maxm = 40000;const int LOG = 18;struct node{    int v, len, nxt;}edge[Maxm << 1];int N, M, cnt, Root;int fir[Maxn + 5], Dep[Maxn + 5], Dis[Maxn + 5];int f[Maxn + 5][LOG];bool getint(int & num){    char c;    int flg = 1;    num = 0;    while((c = getchar()) < '0' || c > '9'){        if(c == '-')    flg = -1;        if(c == -1)     return 0;    }    while(c >= '0' && c <= '9')    {        num = num * 10 + c - 48;        if((c = getchar()) == -1)   return 0;    }    num *= flg;    return 1;}void addedge(int a, int b, int len){    edge[++ cnt].v = b, edge[cnt].len = len, edge[cnt].nxt = fir[a], fir[a] = cnt;}void Dfs(int x, int fa){    Dep[x] = Dep[fa] + 1;    f[x][0] = fa;    for(int i = fir[x]; i; i = edge[i].nxt) if(edge[i].v != fa)        Dis[edge[i].v] = Dis[x] + edge[i].len,        Dfs(edge[i].v, x);}int Get_k(int u, int k){    for(int j = 0; j < LOG; ++ j)        if(k & (1 << j))    u = f[u][j];    return u;}int Get_d(int u, int k){    return Get_k(u, Dep[u] - k);}int LCA(int u, int v){    if(Dep[u] > Dep[v])        u = Get_d(u, Dep[v]);    else if(Dep[u] < Dep[v])        v = Get_d(v, Dep[u]);    if(u == v)  return u;    for(int j = LOG - 1; j >= 0; -- j)  if(f[u][j] != f[v][j])        u = f[u][j], v = f[v][j];    return f[u][0];}int main(){    getint(N), getint(M);    int u, v, l, r;    for(int i = 1; i <= M; ++ i)        getint(u), getint(v), getint(l),        addedge(u, v, l),        addedge(v, u, l);    Root = 1;    Dfs(Root, 0);    for(int j = 1; j < LOG; ++ j)        for(int i = 1; i <= N; ++ i)    f[i][j] = f[f[i][j - 1]][j - 1];    getint(M);    while(M --){        getint(u), getint(v);        r = LCA(u, v);        printf("%d\n", Dis[u] - Dis[r] + Dis[v] - Dis[r]);    }    return 0;}









原创粉丝点击