poj 1986 Distance Queries LCA

题目链接:http://poj.org/problem?id=1986

Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible! 

题目描述:已知n(n<=40000)个农场和一些农场之间的距离,给出很多组询问,在线询问每两个农场之间的距离。

算法分析:这道题运用LCA的在线和离线算法都可以。

离线LCA思路:以某一个农场为树根,用数组保存剩余每个农场到树根的距离为dist[u],那么农场u和v的距离=dist[u]+dist[v]-2*dist[q](q为LCA(u,v))。

我的做法虽然可以AC,但是很慢,有很大的优化空间:在两个节点不断向树根靠近的同时,把每向上走一层的路径上的权值(即农场之间的距离)加起来即为答案。我用离线的LCA代码运用在在线方法上,仔细想想在求每个节点的深度时就可以把离线思想中dist数组求出来了,更简单,速度更快。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<vector>
  8 #define inf 0x7fffffff
  9 using namespace std;
 10 const int maxn=40000+10;
 11 const int max_log_maxn=16;
 12 
 13 int n,m,root;
 14 vector<pair<int,int> > G[maxn];
 15 int father[max_log_maxn][maxn],d[maxn];
 16 int sum[max_log_maxn][maxn];
 17 
 18 void dfs(int u,int p,int depth)
 19 {
 20     father[0][u]=p;
 21     d[u]=depth;
 22     int num=G[u].size();
 23     for (int i=0 ;i<num ;i++)
 24     {
 25         int v=G[u][i].first;
 26         int len=G[u][i].second;
 27         if (v != p)
 28         {
 29             sum[0][v]=len;
 30             dfs(v,u,depth+1);
 31         }
 32     }
 33 }
 34 
 35 void init()
 36 {
 37     dfs(root,-1,0);
 38     for (int k=0 ;k+1<max_log_maxn ;k++)
 39     {
 40         for (int i=1 ;i<=n ;i++)
 41         {
 42             if (father[k][i]<0)
 43             {
 44                 father[k+1][i]=-1;
 45                 sum[k+1][i]=0;
 46             }
 47             else
 48             {
 49                 father[k+1][i]=father[k][father[k][i] ];
 50                 sum[k+1][i]=sum[k][i]+sum[k][father[k][i] ];
 51             }
 52         }
 53     }
 54 }
 55 
 56 int LCA(int u,int v)
 57 {
 58     if (d[u]>d[v]) swap(u,v);
 59     int Sum=0;
 60     for (int k=0 ;k<max_log_maxn ;k++)
 61     {
 62         if ((d[v]-d[u])>>k & 1)
 63         {
 64             Sum += sum[k][v];
 65             v=father[k][v];
 66         }
 67     }
 68     if (u==v) return Sum;
 69     for (int k=max_log_maxn-1 ;k>=0 ;k--)
 70     {
 71         if (father[k][u] != father[k][v])
 72         {
 73             Sum += sum[k][u];
 74             Sum += sum[k][v];
 75             u=father[k][u];
 76             v=father[k][v];
 77         }
 78     }
 79     Sum += sum[0][u];
 80     Sum += sum[0][v];
 81     return Sum;
 82 }
 83 
 84 int main()
 85 {
 86     while (scanf("%d%d",&n,&m)!=EOF)
 87     {
 88         int u,v,length;
 89         char ch[2];
 90         for (int i=0 ;i<=n ;i++) G[i].clear();
 91         for (int i=0 ;i<max_log_maxn ;i++)
 92         {
 93             for (int j=0 ;j<maxn ;j++)
 94                 sum[i][j]=0;
 95         }
 96         for (int i=0 ;i<m ;i++)
 97         {
 98             scanf("%d%d%d%s",&u,&v,&length,ch);
 99             G[u].push_back(make_pair(v,length));
100             G[v].push_back(make_pair(u,length));
101         }
102         root=1;
103         init();
104         int k;
105         scanf("%d",&k);
106         for (int i=0 ;i<k ;i++)
107         {
108             scanf("%d%d",&u,&v);
109             printf("%d\n",LCA(u,v));
110         }
111     }
112     return 0;
113 }

 

posted @ 2015-02-28 22:50  huangxf  阅读(170)  评论(0编辑  收藏  举报