hdu-2586 How far away ?(LCA)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2586

(包括2016级新生)除了校赛,还有什么途径可以申请加入ACM校队?

How far away ?

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


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-1条路,求任意两点间最短路。用最短路算法可以求。。不过询问次数太多,所以可能会超时。想到用LCA。

注意题目有误,题目说每个测试样例后面要输出空行,但是样例并没有输出。所以不用空行

用l[i]表示i到根节点的距离。那么要求a和b点的距离就是l[a]+l[b]-2*[lca[a,b]]  我用的在线算法

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 40010
int dp[2*N][20];
int head[N],p[N];
int dep[2*N],f[2*N];
int flag[N],cnt;
int l[N];
struct Edge
{
    int to,next;
    int len;
} edge[2*N];
void init(int n)
{
    cnt=0;
    for(int i=0; i<=n; i++)
    {
        head[i]=-1;
        flag[i]=0;
    }
    memset(l,0,sizeof(l));
}
void addedge(int s,int e,int len)
{
    edge[cnt].to=e;
    edge[cnt].next=head[s];
    edge[cnt].len=len;
    head[s]=cnt++;
}
void dfs(int u,int d)
{
    f[cnt]=u;
    dep[cnt]=d;
    p[u]=cnt++;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        l[v]=l[u]+edge[i].len;
        dfs(v,d+1);
        f[cnt]=u;
        dep[cnt++]=d;
    }
}
void makermq()
{
    for(int i=0; i<cnt; i++)
        dp[i][0]=i;
    for(int j=1; (1<<j)<=cnt; j++)
    {
        for(int i=0; i+(1<<j)-1<cnt; i++)
        {
            if(dep[dp[i][j-1]]<dep[dp[i+(1<<(j-1))][j-1]])
                dp[i][j]=dp[i][j-1];
            else
                dp[i][j]=dp[i+(1<<(j-1))][j-1];
        }
    }
}
int finds(int s,int e)
{
    if(s>e)
    {
        int t=s;
        s=e;
        e=t;
    }
    int k=(int)(log(e-s+1.0)/log(2.0));
    if(dep[dp[s][k]]<dep[dp[e-(1<<k)+1][k]])
        return dp[s][k];
    return dp[e-(1<<k)+1][k];
}
void LCA(int root,int n,int m)
{
    cnt=0;
    dfs(root,0);
    makermq();
    int s,e;
    while(m--)
    {
        scanf("%d %d",&s,&e);
    int t=f[finds(p[s],p[e])];
    printf("%d\n",l[s]+l[e]-2*l[t]);
    }
}
int main()
{
    int T,n,m,len;
    int s,e,root;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        init(n);
        for(int i=1; i<n; i++)
        {
            scanf("%d %d %d",&s,&e,&len);
            addedge(s,e,len);
            flag[e]=1;
        }
        for(int i=1; i<=n; i++)
            if(!flag[i])
            {
                root=i;
                break;
            }
        LCA(root,n,m);
    }
    return 0;
}


你可能感兴趣的:(ACM,HDU)