【37.48%】【hdu 2587】How far away ?(3篇文章,3种做法,LCA之ST算法(RMQ))

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13390 Accepted Submission(s): 5018

Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.

Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.

Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.

Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1

Sample Output
10
25
100
100

【题解】

设p[i][j]表示从i时间戳开始2^j个时间戳范围内高度最小的一个节点的编号;
//这个东西可以用求RMQ的方法搞出来。
找到要求的两个节点第一次出现的时间戳x,y;
并确保x小于y;
p[x][k]和p[y-k+1][k])
取这两个节点中高度较小的就是x和y的最近公共祖先了;
其中k是y-x+1这个距离,要用2的多少次方表示;
找到祖先后输出dis[x]+dis[y]-2*dis[LCA];就是距离了。
这个距离是树上的最短距离。还是很有用的。可以扩展下;

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 50000;
const int MAX = 16;

vector <int> son[MAXN],w[MAXN];
int n,p[MAXN*4][MAX+5],dep[MAXN],pre[MAX+5],m,cnt,fir[MAXN],shall[MAXN*4];
long long dis[MAXN];

void input(int &r)
{
    char t = getchar();
    while (!isdigit(t)) t = getchar();
    r = 0;
    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
}

void dfs(int x,int f)
{
    dep[x] = dep[f] + 1;
    p[++cnt][0] = x;
    fir[x] = cnt;
    int len = son[x].size();
    for (int i = 0; i <= len - 1; i++)
    {
        int y = son[x][i];
        if (y != f)
        {
            dis[y] = dis[x] + w[x][i];
            dfs(y, x);
            p[++cnt][0] = x;
        }
    }
}

int main()
{
    //freopen("F:\rush.txt", "r", stdin);
    pre[0] = 1;
    for (int i = 1; i <= MAX; i++)
        pre[i] = pre[i - 1] << 1;
    int T;
    input(T);
    while (T--)
    {
        cnt = 0;
        input(n); input(m);
        for (int i = 1; i <= n; i++)
            son[i].clear(),w[i].clear();
        for (int i = 1; i <= n - 1; i++)
        {
            int x, y, z;
            input(x); input(y); input(z);
            son[x].push_back(y);
            w[x].push_back(z);
            son[y].push_back(x);
            w[y].push_back(z);
        }
        dis[1] = 0;
        dfs(1, 0);
        shall[1] = 0;
        shall[2] = 1;
        int top = 2;
        for (int i = 3; i <= cnt; i++)
        {
            if (i == pre[top])
                shall[i] = shall[i - 1] + 1;
            else
                shall[i] = shall[i - 1];
        }
        for (int j = 1;j <= MAX;j++)
            for (int i = 1; i +pre[j-1]<= cnt; i++)
            {
                int a = p[i][j - 1];
                int b = p[i + pre[j - 1]][j - 1];
                if (dep[a] < dep[b])
                    p[i][j] = a;
                else
                    p[i][j] = b;
            }
        for (int i = 1; i <= m; i++)
        {
            int x, y,px,py;
            input(x); input(y);
            px = x, py = y;
            x = fir[x], y = fir[y];
            if (x > y)
                swap(x, y);
            int k = shall[y - x + 1];
            int lca;
            int ll, rr;
            ll = p[x][k];
            rr = p[y - pre[k] + 1][k];
            if (dep[ll] < dep[rr])
                lca = ll;
            else
                lca = rr;
            printf("%I64d
", dis[px] + dis[py] - 2 * dis[lca]);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/7632177.html