【LCA求最短距离】hdu 2586 How far away ?

来源:互联网 发布:cf刷枪软件永久 编辑:程序博客网 时间:2024/06/05 07:15

How far away ?

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


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
23 21 2 103 1 151 22 32 21 2 1001 22 1
 

Sample Output
1025100100
 

这个题比普通的LCA只多了一个求距离,然后就把我华丽丽的困住了==

当然了,我用的LCA是离线版的并查集那种模板是邝斌的那种,

LCA 不难理解,就是dfs树+并查集 ,但是距离加在哪里??

机智如我想到了在递归的时候求~然而写进去还找错位置了,

原因在于应该写成dis[v]=dis[u]+edge[i].len;而不是dis[v]+=edge[i].len;

然后就是距离的求法dis[u] + dis[v] - 2 * dis[ans(u, v)]


#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;const int maxn = 40005; //顶点数const int maxq = 205; //最多查询次数,根据题目而定,本题中其实每组数据只有一个查询.//并查集int f[maxn];//根节点int find(int x){    if (f[x] == -1)    {        return x;    }    return f[x] = find(f[x]);}void unite(int u, int v){    int x = find(u);    int y = find(v);    if (x != y)    {        f[x] = y;    }}//并查集结束bool vis[maxn];//节点是否访问int ancestor[maxn];//节点i的祖先struct Edge{    int to, next, len;} edge[maxn * 2];int head[maxn], tot;void addedge(int u, int v, int length) //邻接表头插法加边{    edge[tot].to = v;    edge[tot].len = length;    //  printf("%d  ",length);    edge[tot].next = head[u];    head[u] = tot++;}struct Query{    int q, next;    int index;//查询编号,也就是输入的顺序} query[maxq * 2];int ans[maxn * 2]; //存储每次查询的结果,下表0~Q-1,其实应该开maxq大小的。int h[maxn], tt;int Q;//题目中需要查询的次数int dis[maxn];void addquery(int u, int v, int index) //邻接表头插法加询问{    query[tt].q = v;    query[tt].next = h[u];    query[tt].index = index;    h[u] = tt++;    query[tt].q = u; //相当于两次查询,比如查询  3,5 和5,3结果是一样的,以3为头节点的邻接表中有5,以5为头节点的邻接表中有3    query[tt].next = h[v];    query[tt].index = index;    h[v] = tt++;}void init(){    tot = 0;    memset(head, -1, sizeof(head));    tt = 0;    memset(h, -1, sizeof(h));    memset(vis, 0, sizeof(vis));    memset(f, -1, sizeof(f));    memset(ancestor, 0, sizeof(ancestor));    memset(dis, 0, sizeof(dis));}void LCA(int u){    ancestor[u] = u;    vis[u] = true;    for (int i = head[u]; i != -1; i = edge[i].next) //和顶点u相关的顶点    {        int v = edge[i].to;        // printf("%d    ",edge[i].len);        if (vis[v])        {            continue;        }        //dis[v]+=edge[i].len;        dis[v] = dis[u] + edge[i].len;        LCA(v);        unite(u, v);        ancestor[find(u)] = u; //将u的左右孩子的祖先设为u        //dis[find(u)]+=dis[u];    }    for (int i = h[u]; i != -1; i = query[i].next) //看输入的查询里面有没有和u节点相关的    {        int v = query[i].q;        if (vis[v])        {            ans[query[i].index] = ancestor[find(v)];        }    }}bool flag[maxn];//用来确定根节点的int t;int n, u, v, len;int main(){    scanf("%d", &t);    while (t--)    {        scanf("%d%d", &n, &Q);        init();        memset(flag, 0, sizeof(flag));        for (int i = 1; i < n; i++)        {            scanf("%d%d%d", &u, &v, &len);            flag[v] = true; //有入度            addedge(u, v, len);            addedge(v, u, len);        }        for (int i = 0; i < Q; i++)        {            scanf("%d%d", &u, &v);            addquery(u, v, i);        }        int root;        for (int i = 1; i <= n; i++)        {            if (!flag[i])            {                root = i;                //  printf("root=%d  ",root);                break;            }        }        LCA(root);        //  for(int i=1;i<=n;i++)printf("%d  ",dis[i]); printf("\n");        for (int i = 0; i < Q; i++)        {            len = dis[query[i << 1].q] + dis[query[i << 1 | 1].q] - dis[ans[i]] * 2;            printf("%d\n", len);        }    }    return 0;}


原创粉丝点击