HDU 2586 How far away ?(lca)

来源:互联网 发布:cf卡数据恢复 mac 编辑:程序博客网 时间:2024/06/05 08:25

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之间的距离是多少。

思路:lca模板题

代码如下

模板一:

#include <iostream>  #include <cstdio>  #include <cstring>  #include <cmath>  #include <algorithm>using namespace std;  const int N = 40010;  const int M = 25;  int dp[2*N][M];  //这个数组记得开到2*N,因为遍历后序列长度为2*n-1  bool vis[N];  struct edge  {      int v,w,next;  }e[2*N];  //链式向前星存边int tot,head[N];  int tol; inline void add(int u ,int v ,int w )  {      e[tol].v = v; e[tol].w = w;      e[tol].next = head[u]; head[u] = tol++;      u = u^v; v = u^v; u = u^v;      e[tol].v = v; e[tol].w = w;      e[tol].next = head[u]; head[u] = tol++;  }  int ver[2*N],R[2*N],first[N],dir[N];  //ver:节点编号 R:深度 first:点编号位置 dir:距离  void dfs(int u ,int dep)  {      vis[u] = true; ver[++tot] = u; first[u] = tot; R[tot] = dep;      for(int k=head[u]; k!=-1; k=e[k].next)          if( !vis[e[k].v] )          {              int v = e[k].v , w = e[k].w;              dir[v] = dir[u] + w;              dfs(v,dep+1);              ver[++tot] = u; R[tot] = dep;          }  }  void ST(int n)  {      for(int i=1;i<=n;i++)          dp[i][0] = i;      for(int j=1;(1<<j)<=n;j++)      {          for(int i=1;i+(1<<j)-1<=n;i++)          {              int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];              dp[i][j] = R[a]<R[b]?a:b;          }      }  }  //中间部分是交叉的。  int RMQ(int l,int r)  {      int k=0;      while((1<<(k+1))<=r-l+1)          k++;      int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号      return R[a]<R[b]?a:b;  }  int LCA(int u ,int v)  {      int x = first[u] , y = first[v];      if(x > y) swap(x,y);      int res = RMQ(x,y);      return ver[res];  }  int main()  {      int cas;      scanf("%d",&cas);      while(cas--)      {          int n,q;          tol=0;        scanf("%d%d",&n,&q);          memset(head,-1,sizeof(head));          memset(vis,false,sizeof(vis));          for(int i=1; i<n; i++)          {              int u,v,w;              scanf("%d%d%d",&u,&v,&w);              add(u,v,w);          }          tot = 0; dir[1] = 0;          dfs(1,1);          ST(2*n-1);          while(q--)          {              int u,v;              scanf("%d%d",&u,&v);              int lca = LCA(u,v);              printf("%d\n",dir[u] + dir[v] - 2*dir[lca]);          }      }      return 0;  }  

模板二:

#include <cstdio>  #include <cstdlib>  #include <cstring>  #include <cmath>  #include <algorithm>  #include <iostream>  #include <string>  #include <vector>  using namespace std;  const int N=40005;const int M=40005;int head[N];int dis[N];int deep[N],fa[N],pre[N];int n,m,q,tol;bool vis[N];struct Edge//链式向前星存边 {    int to,cost;    int next;}edge[M*2];void addedge(int u,int v,int cost){    edge[tol].to=v;    edge[tol].cost=cost;    edge[tol].next=head[u];    head[u]=tol++;}void dfs(int s){    vis[s]=1;    for(int i=head[s];i!=-1;i=edge[i].next)    {        int to=edge[i].to;        if(!vis[to])        {            fa[to]=s;            deep[to]=deep[s]+1;            dis[to]=dis[s]+edge[i].cost;            dfs(to);        }    }}int lca(int x,int y){    if(deep[x]>deep[y]) swap(x,y);    while(deep[x]!=deep[y])    {        y=fa[y];    }    while(x!=y)    {        x=fa[x];        y=fa[y];        //cout<<x<<' '<<y<<endl;    }    return x;}void init(){    memset(head,-1,sizeof(head));    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)     {       pre[i]=i;       dis[i]=0;    }      tol=0;}int main(){    int T;    scanf("%d",&T);    while(T--)    {    scanf("%d%d",&n,&q);    init();    int u,v,cost;    for(int i=1;i<=n-1;i++)    {       scanf("%d%d%d",&u,&v,&cost);       addedge(u,v,cost);       addedge(v,u,cost);    }    dfs(1);//建树     for(int i=1;i<=q;i++)    {        int u,v;        scanf("%d%d",&u,&v);        printf("%d\n",dis[u]+dis[v]-dis[lca(u,v)]*2);    } }    return 0;}
原创粉丝点击