ACM: 最近公共祖先tarjan poj 1986

来源:互联网 发布:厦门淘宝代运营 编辑:程序博客网 时间:2024/05/22 10:30
DistanceQueries

 

Description

Farmer John's cows refused torun in his marathon since he chose a path much too long for theirleisurely lifestyle. He therefore wants to find a path of a morereasonable length. The input to this problem consists of the sameinput as in "Navigation Nightmare",followed by a line containing asingle integer K, followed by K "distance queries". Each distancequery is a line of input containing two integers, giving thenumbers of two farms between which FJ is interested in computingdistance (measured in the length of the roads along the pathbetween the two farms). Please answer FJ's distance queries asquickly as possible!

Input

* Lines 1..1+M: Same format as"Navigation Nightmare"

* Line 2+M: A single integer, K. 1 <= K<= 10,000

* Lines 3+M..2+M+K: Each line corresponds to a distance query andcontains the indices of two farms.

Output

* Lines 1..K: For each distancequery, output on a single line an integer giving the appropriatedistance.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6

Sample Output

13
3
36

题意: 在一棵树上, 找出多个点对之间的最短距离.

 

解题思路:

       1.树上找出点对之间的最短距离, 显然是LCA问题.

       2.tarjan算法求解最近公共祖先问题. 最短距离: dist[u] + dist[v] - 2*dist[LCA(u,v)];

       3.一开始是先将每个点的前驱找出, 并且分等级的前驱. 再用二分来找出最近公共祖先.

             结果是一直TLE了,悲剧啊,T.T. 数据太大了.

       4.后面在网上看别人的题解和黑书上面pag 55 得到启发,直接再dfs的时候就将每个结果保持起来即可.

         问题分析: 经典的tarjan算法

           void LCA(u)

           {

               vis[u] = true;

               make_set(u);

               ancestor[ find_set(u) ] = u;

               for(u的每个孩子v)

               {

                    if( 如果v未访问 )

                     {

                         LCA(u,v);

                         union(u,v);

                         ancestor[find_set(u)] = u;

                     }

               }

               flag[u] = true;

               for(Q(u)中所有元素v)

                {

                   if(flag[v] == true)

                   {

                      printf("LCA(%d %d) = %d\n",u,v,ancestor[find_set(v)]);

                   }

               }

            }

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 80005

struct node
{
 int u, v;
 int w;
 int next;
 int ans;
}edges[MAX], qu[MAX];

int n, m;
int num1, num2;
int p[MAX], dist[MAX];
int first1[MAX], first2[MAX];
bool flag[MAX], vis[MAX];


inline void add1(int u,int v,int w)
{
 edges[num1].u = u;
 edges[num1].v = v;
 edges[num1].w = w;
 edges[num1].ans = 0;
 edges[num1].next = first1[u];
 first1[u] = num1++;
}

inline void add2(int u,int v)
{
 qu[num2].u = u;
 qu[num2].v = v;
 qu[num2].ans = 0;
 qu[num2].next = first2[u];
 first2[u] = num2++;
}

int find(int x)
{
 return x == p[x] ? x : (p[x] = find(p[x]));
}

void read_graph()
{
 int i;
 int u, v, w;
 char ch;
 num1 = 0;
 memset(first1,-1,sizeof(first1));
 memset(first2,-1,sizeof(first2));
 memset(flag,false,sizeof(flag));
 memset(vis,false,sizeof(vis));

 for(i = 1; i <= m; ++i)
 {
  scanf("%d %d %d%c",&u,&v,&w,&ch);
  add1(u,v,w);
  add1(v,u,w);
 }

 int caseNum;
 num2 = 0;
 scanf("%d",&caseNum);
 for(i = 1; i <= caseNum;++i)
 {
  scanf("%d%d",&u,&v);
  add2(u,v);
  add2(v,u);
 }
}

void LCA(int x)
{
 int v, e, i;
 vis[x] = true;
 p[x] = x; //merge;
 for(i = first1[x]; i != -1; i =edges[i].next)
 {
  v = edges[i].v;
  if(!vis[v])
  {
   dist[v] =dist[x] + edges[i].w;
   LCA(v);
   p[v] =x;
  }
 }

 flag[x] = true;
 for(i = first2[x]; i != -1; i = qu[i].next)
 {
  v = qu[i].v;
  if(flag[v])
  {
   e =find(v);
   qu[i].ans =dist[v] + dist[x] - 2*dist[e];
  }
 }
}

int main()
{
// freopen("input.txt","r",stdin);
 while(scanf("%d%d",&n,&m) != EOF)
 {
  read_graph();

  dist[1] = 0;
  LCA(1);

  for(int k = 0; k< num2; ++k)
  {
   if(qu[k].ans|| qu[k].u == qu[k].v)
   {
    printf("%d\n",qu[k].ans);
    if(qu[k].u== qu[k].v)
     k++;
   }
  }
 }
 return 0;
}

 

 

 

 

-------------------------------------------------------------------------------------------------

 

 

附上一个超时的代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005

struct node
{
 int v;
 int w;
 int next;
}edges[MAX*2];

int n, m;
int p[MAX][200], deep[MAX];
int first[MAX], num;
int dist[MAX];
int du[MAX], start;

inline void add(int u, int v, int w)
{
 edges[num].v = v;
 edges[num].w = w;
 edges[num].next = first[u];
 first[u] = num++;
}

void read_graph()
{
 memset(p,0,sizeof(p));
 memset(first,-1,sizeof(first));
 num = 0;

 for(int j = 1; j <= n;++j)
  du[j] = deep[j] = dist[j] =0;;

 int u, v, w;
 char ch;
 for(int i = 1; i <= m; ++i)
 {
  scanf("%d %d %d%c",&u,&v,&w,&ch);
  if(ch == 'S' || ch =='E')
  {
   add(u,v,w);
   du[v] =1;
  }
  else
  {
   add(v,u,w);
   du[u] =1;
  }
 }

 for(int k = 1; k <= n;++k)
 {
  if(du[k] == 0)
  {
   start =k;
   break;
  }
 }
}

void dfs(int u,int distance)
{
 if(first[u] == -1) return ;
 for(int e = first[u]; e != -1; e =edges[e].next)
 {
  int v = edges[e].v;
  dist[v] = distance +edges[e].w;
  p[v][0] = u;
  int m = u;
  deep[v] = deep[u]+1;
  for(int j = 0; p[m][j] != 0;++j)
  {
   p[v][j+1] =p[m][j];
   m =p[m][j];
  }
  dfs(v,dist[v]);
 }
}

int LCA(int x,int y)
{
 int m, k;
 if(x == y) return x;
 if(deep[x] < deep[y])
 {
  m = x; x = y; y = m;
 }
 m = deep[x] - deep[y];
 k = 0;
 while( m )
 {
  if(m & 1) x =p[x][k];
  m>>= 1;
  k++;
 }
 if(x == y) return x;
 k = 0;
 while(x != y)
 {
  if(p[x][k] != p[y][k] ||p[x][k] == p[y][k] && k == 0)
  {
   x =p[x][k];
   y =p[y][k];
   k++;
  }
  else k--;
 }
 return x;
}

int main()
{
// freopen("input.txt","r",stdin);
 while(scanf("%d%d",&n,&m) != EOF)
 {
  read_graph();
  dfs(start,0);

  int caseNum;
  int u, v;
  scanf("%d",&caseNum);
  for(int i = 0; i< caseNum; ++i)
  {
   scanf("%d%d",&u,&v);
   printf("%d\n",dist[u]+ dist[v] - 2*dist[LCA(u,v)]);
  }
 }
 return 0;
}

 

0 0