hdu2586 How far away ? 【圖論-Tarjan-Lca】

                                How far away ?

 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

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(0 < k <= 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

題目大意:一個村子裏有n個房子,這n個房子用n-1條路連接起來,接下了有m次詢問,每次詢問兩個房子a,b之間的距離是多少。
很明顯的最近公共祖先問題,先建一棵樹,然後求出每一點i到樹根的距離dis[i],然後每次詢問a,b之間的距離=dis[a]+dis[b]-2*dis[LCA(a,b)];
LCA(a,b)即是a,b的最近公共祖先。。

AC代碼1:

# include <stdio.h>
# include <string.h>
# include <cmath>
# include <algorithm>

using namespace std;

# define MAXN 400005

struct EDGE
{
    int v;
    int w;
    int next;
}edge[MAXN]; //鄰接表存放圖結構

int tot;
int head[MAXN];
int vis[MAXN];
int pre[MAXN];
int depth[MAXN];
int dis[MAXN];
int parent[MAXN][25];

void Init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}

void Addedge(int u, int v, int w)
{
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void dfs(int u, int father, int d) //搜索  把圖結構裝換成樹結構
{
    depth[u] = d;
    pre[u] = father;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].v;
        if (v != father)
        {
            dis[v] = dis[u] + edge[i].w;
            dfs(v, u,  d+1);
        }
    }
}

void LcaInit(int n)
{
    int i, j;
    for (j = 0; (1 << j) <= n; j++)
    {
        for (i = 1; i <= n; i++)
        {
            parent[i][j] = -1;
        }
    }
    for (i = 1; i <= n; i++)
    {
        parent[i][0] = pre[i];
    }
    for (j = 1; (1 << j) <= n; j++)
    {
        for (i = 1; i <= n; i++)
        {
            if (parent[i][j - 1] != -1)
            {
                parent[i][j] = parent[parent[i][j - 1]][j - 1];
            }
        }
    }
}

int Lca(int a, int b) //求公共祖先
{
    int i, j;
    if (depth[a] < depth[b])
    {
        swap(a, b);
    }
    for (i = 0; (1 << i) <= depth[a]; i++);
    i--;
    for (j = i; j >= 0; j--)
    {
        if (depth[a] - depth[b] >= (1 << j))
        {
            a = parent[a][j];
        }
    }
    if (a == b)
    {
        return a;
    }
    for (j = i; j >= 0; j--)
    {
        if (parent[a][j] != -1 && parent[a][j] != parent[b][j])
        {
            a = parent[a][j];
            b = parent[b][j];
        }
    }
    return pre[a];
}

int main(void)
{
    int t;
    int i, j;
    scanf("%d", &t);
    while (t--)
    {
        int n, m;
        int u, v, w;
        scanf("%d %d", &n, &m);
        Init();
        for (int i = 1; i < n; i++)
        {
            scanf("%d %d %d", &u, &v, &w);
            Addedge(u, v, w);
            Addedge(v, u, w);
        }
        dis[1] = 0;
        dfs(1, -1, 0);
        LcaInit(n);
        int ans = 0;
        for (i = 0; i < m; i++)
        {
            scanf("%d %d", &u, &v);
            ans = dis[u] + dis[v] - 2 * dis[Lca(u, v)];
            printf("%d\n", ans);
        }

    }
    return 0;
}

AC代碼2:

# include <stdio.h>
# include <string.h>
# include <cmath>
# include <vector>
# include <algorithm>

using namespace std;

# define MAXN 40005

struct node{
    int v, w;
    node(int a = 0, int b = 0){ v = a; w = b; }
};
vector<node> edge[MAXN];  //使用vector容器存放圖結構

int vis[MAXN];
int pre[MAXN];
int depth[MAXN];
int dis[MAXN];
int parent[MAXN][25];


void dfs(int u, int father, int d) //圖轉樹
{
    depth[u] = d;
    pre[u] = father;
    int num = edge[u].size();
    for (int i = 0; i < num; i++)
    {
        int v = edge[u][i].v;
        if (v != father)
        {
            dis[v] = dis[u] + edge[u][i].w;
            dfs(v, u, d + 1);
        }
    }
}

void LcaInit(int n)
{
    int i, j;
    for (j = 0; (1 << j) <= n; j++)
    {
        for (i = 1; i <= n; i++)
        {
            parent[i][j] = -1;
        }
    }
    for (i = 1; i <= n; i++)
    {
        parent[i][0] = pre[i];
    }
    for (j = 1; (1 << j) <= n; j++)
    {
        for (i = 1; i <= n; i++)
        {
            if (parent[i][j - 1] != -1)
            {
                parent[i][j] = parent[parent[i][j - 1]][j - 1];
            }
        }
    }
}

int Lca(int a, int b)
{
    int i, j;
    if (depth[a] < depth[b])
    {
        swap(a, b);
    }
    for (i = 0; (1 << i) <= depth[a]; i++);
    i--;
    for (j = i; j >= 0; j--)
    {
        if (depth[a] - depth[b] >= (1 << j))
        {
            a = parent[a][j];
        }
    }
    if (a == b)
    {
        return a;
    }
    for (j = i; j >= 0; j--)
    {
        if (parent[a][j] != -1 && parent[a][j] != parent[b][j])
        {
            a = parent[a][j];
            b = parent[b][j];
        }
    }
    return pre[a];
}

int main(void)
{
    int t;
    int i, j;
    scanf("%d", &t);
    while (t--)
    {
        int n, m;
        int u, v, w;
        scanf("%d %d", &n, &m);
        for (i = 1; i <= n; i++)
        {
            edge[i].clear();
        }
        for (i = 1; i < n; i++)
        {
            scanf("%d %d %d", &u, &v, &w);
            edge[u].push_back(node(v, w));
            edge[v].push_back(node(u, w));
        }
        dis[1] = 0;
        dfs(1, -1, 0);
        LcaInit(n);

        int ans = 0;

        for (i = 0; i < m; i++)
        {
            scanf("%d %d", &u, &v);
            ans = dis[u] + dis[v] - 2 * dis[Lca(u, v)];
            printf("%d\n", ans);
        }

    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章