poj1986 (LCA)

poj1986

给我们一棵树,求任意两个点之间的距离

dist[a->b] = dist[a] +dist[b] - 2*lca(a,b)

要建双向边,数据可能不是严格意义上的树

  1 #include <stdio.h>

  2 #include <string.h>

  3 #include <stdlib.h>

  4 #include <algorithm>

  5 #include <iostream>

  6 #include <queue>

  7 #include <stack>

  8 #include <vector>

  9 #include <map>

 10 #include <set>

 11 #include <string>

 12 #include <math.h>

 13 using namespace std;

 14 #pragma warning(disable:4996)

 15 typedef long long LL;                   

 16 const int INF = 1<<30;

 17 /*

 18 

 19 */

 20 struct Edge

 21 {

 22     int to,dist;

 23 };

 24 const int MAX_LOG_V = 100;

 25 const int MAX_V = 100000+10;

 26 int parent[MAX_LOG_V][MAX_V];

 27 int depth[MAX_V];

 28 int dist[MAX_V];

 29 vector<Edge> g[MAX_V];

 30 void dfs(int u, int fa, int d)

 31 {

 32     parent[0][u] = fa;

 33     depth[u] = d;

 34     for(int i=0; i<g[u].size(); ++i)

 35         if(g[u][i].to!=fa)

 36         {

 37             dist[g[u][i].to] = dist[u] + g[u][i].dist;

 38             dfs(g[u][i].to,u,d+1);

 39         }    

 40 }

 41 void init(int root, int n)

 42 {

 43     dfs(root,-1,0);

 44     //预处理出parent

 45     for(int k=0; k+1<MAX_LOG_V; ++k)

 46     {

 47         for(int v=1; v<=n; ++v)

 48         {

 49             if(parent[k][v]<0)

 50                 parent[k+1][v] = -1;

 51             else

 52                 parent[k+1][v] = parent[k][parent[k][v]];

 53         }

 54     }

 55 }

 56 int lca(int u, int v)

 57 {

 58     if(depth[u] < depth[v])

 59         swap(u,v);

 60     //让u和v走到同一生度

 61     for(int k=0; k<MAX_LOG_V; ++k)

 62         if((depth[u]-depth[v])>>k&1)//一个数能分解成多个二进制数相加,所以如果&1 为true,那么就向上走

 63             u = parent[k][u];

 64     if(u==v) return u;

 65     //达到同一深度后,二分搜索lca

 66     

 67     for(int k=MAX_LOG_V-1; k>=0; --k)

 68         if(parent[k][v]!=parent[k][u])

 69         {//我们并不知道要向上走多少步,但是只要每次走后,

 70         //parent[k][v]!=parent[k][u],那么这一步就可以向上走,即将要走的步数分解为 1 + 2 + 4 + 8 + ...最后一步将在循环结束后走出

 71             u = parent[k][u];

 72             v = parent[k][v];

 73         }

 74     return parent[0][u];

 75 }

 76 

 77 int main()

 78 {

 79     int n,a,m,i,b,t,root,c;

 80     char str[2];

 81     Edge tmp;

 82     while(scanf("%d%d",&n,&m)!=EOF)

 83     {

 84         

 85         for(i=1; i<=n; ++i)

 86         {

 87             parent[0][i] = -1;

 88             g[i].clear();

 89         }

 90         for(i=0; i<n-1; ++i)

 91         {

 92             scanf("%d%d%d%s",&a,&b,&c,str);

 93             tmp.to = b;

 94             tmp.dist = c;

 95             g[a].push_back(tmp);

 96             tmp.to = a;

 97             g[b].push_back(tmp);

 98         }

 99         root = 1;

100         dist[root] = 0;

101         init(root,n);

102         scanf("%d",&m);

103         for(i=0; i<m; ++i)

104         {

105             scanf("%d%d",&a,&b);

106             int LCA = lca(a,b);

107             printf("%d\n",dist[a]-dist[LCA] + dist[b]-dist[LCA]);

108         }

109         

110         

111     }

112     

113     return 0;

114 }

 

你可能感兴趣的:(poj)