BZOJ 1602 [Usaco2008 Oct]牧场行走

Description

N头牛(2<=n<=1000)别人被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头牛在第i块牧场吃草。
这n块土地被n-1条边连接。 奶牛可以在边上行走,第i条边连接第Ai,Bi块牧场,第i条边的长度是Li(1<=Li<=10000)。
这些边被安排成任意两头奶牛都可以通过这些边到达的情况,所以说这是一棵树。
这些奶牛是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q(1<=q<=1000)对奶牛之间的距离。

Input

*第一行:两个被空格隔开的整数:N和Q

*第二行到第n行:第i+1行有两个被空格隔开的整数:AI,BI,LI

*第n+1行到n+Q行:每一行有两个空格隔开的整数:P1,P2,表示两头奶牛的编号。

Output

*第1行到第Q行:每行输出一个数,表示那两头奶牛之间的距离。

Sample Input

4 2

2 1 2

4 3 2

1 4 3

1 2

3 2

Sample Output

2

7

HINT

Source

资格赛

lca

#include <iostream>
#include <cstdio>
using namespace std;
const int SZ = 1010;

struct Edge
{
    int f, t, d;
}es[SZ << 1];
int first[SZ << 1], nxt[SZ << 1], tot = 1;
int depth[SZ], fa[SZ], dis[SZ], jump[SZ][20];

void build(int f, int t, int d)
{
    es[++tot] = (Edge){f, t ,d};
    nxt[tot] = first[f];
    first[f] = tot;
}

void dfs(int u, int f)
{
    depth[u] = depth[f] + 1;
    fa[u] = f;
    jump[u][0] = f;
    for(int i = 1; i <= 16; i++)
        jump[u][i] = jump[jump[u][i - 1]][i - 1];   
    for(int i = first[u]; i; i = nxt[i])
    {
        int v = es[i].t;
        if(v == f) continue;
        dis[v] = dis[u] + es[i].d;
        dfs(v, u);
    }
}

int lca(int l, int r)
{
    if(depth[l] < depth[r]) swap(l, r);
    int t = depth[l] - depth[r];
    for(int i = 0; i <= 16; i++)
        if(t & (1 << i)) l = jump[l][i];
    for(int i = 16; i >= 0; i--)
        if(jump[l][i] != jump[r][i])
            l = jump[l][i], r = jump[r][i];
    if(l == r) return l;
    return jump[l][0];
}

int main()
{
    int n, q;
    scanf("%d%d", &n, &q);
    int f, t, d;
    for(int i = 1; i < n; i++)
    {
        scanf("%d%d%d", &f, &t, &d);
        build(f, t, d);
        build(t, f, d);
    }
    dfs(1, 0);
    for(int i = 1; i <= q; i++)
    {
        scanf("%d%d", &f, &t);
        int F = lca(f, t);
        int ans = dis[f] + dis[t] - 2 * dis[F];
        printf("%d\n", ans);
    }
    return 0;
}

posted @ 2016-09-10 06:32  Loi_Vampire  阅读(84)  评论(0编辑  收藏  举报