Poj--1986(LCA,tarjan,带权树)

2014-10-26 16:17:09

思路:方向啥的不用管,直接双向边。注意,这样的构建的图是无向无根的树,我们要任选一个点做根将其转化为有根树即可,并且在DFS中不能回到父亲节点,这样就和正常的有向有根树一样了。另外这题的边是带权的,所以点的深度其实就是路径权和。

  1 /*************************************************************************
  2     > File Name: 1986.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com 
  5     > Created Time: Sun 26 Oct 2014 03:30:27 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <stack>
 16 #include <queue>
 17 #include <iostream>
 18 #include <algorithm>
 19 using namespace std;
 20 #define lp (p << 1)
 21 #define rp (p << 1|1)
 22 #define getmid(l,r) (l + (r - l) / 2)
 23 #define MP(a,b) make_pair(a,b)
 24 typedef long long ll;
 25 const int INF = 1 << 30;
 26 const int maxn = 40010;
 27 
 28 int n,m,k;
 29 int first[maxn],next[maxn << 1],ver[maxn << 1],w[maxn << 1],ecnt;
 30 int vis[maxn],fa[maxn],dep[maxn];
 31 int ans[10010];
 32 vector< pair<int,int> > g[maxn];
 33 
 34 void Init(){
 35     memset(first,-1,sizeof(first));
 36     for(int i = 1; i <= n; ++i)
 37         g[i].clear();
 38     ecnt = 0;
 39 }
 40 
 41 void Add_edge(int u,int v,int c){
 42     next[++ecnt] = first[u];
 43     ver[ecnt] = v;
 44     w[ecnt] = c;
 45     first[u] = ecnt;
 46 }
 47 
 48 int Find(int x){
 49     return fa[x] == x ? x : fa[x] = Find(fa[x]);
 50 }
 51 
 52 void Union(int u,int v){
 53     int x = Find(u);
 54     int y = Find(v);
 55     if(x != y)
 56         fa[y] = x;
 57 }
 58 
 59 void Tarjan(int p,int pre,int d){
 60     dep[p] = d;
 61     fa[p] = p;
 62     for(int i = first[p]; i != -1; i = next[i]){
 63         int v = ver[i];
 64         if(v != pre){
 65             Tarjan(v,p,d + w[i]);
 66             Union(p,v);
 67         }
 68     }
 69     vis[p] = 1;
 70     for(int i = 0; i < g[p].size(); ++i){
 71         int v = g[p][i].first;
 72         if(vis[v]){
 73             int lca = Find(v);
 74             int id = g[p][i].second;
 75             ans[id] = dep[p] + dep[v] - 2 * dep[lca];
 76         }
 77     }    
 78 }
 79 
 80 int main(){
 81     char d;
 82     int a,b,c;
 83     scanf("%d%d",&n,&m);
 84     Init();
 85     for(int i = 1; i <= m; ++i){
 86         scanf("%d %d %d %c",&a,&b,&c,&d);
 87         Add_edge(a,b,c);
 88         Add_edge(b,a,c);
 89     }
 90     scanf("%d",&k);
 91     for(int i = 1; i <= k; ++i){
 92         scanf("%d%d",&a,&b);
 93         g[a].push_back(MP(b,i));
 94         g[b].push_back(MP(a,i));
 95     }
 96     Tarjan(1,0,0);
 97     for(int i = 1; i <= k; ++i)
 98         printf("%d\n",ans[i]);
 99     return 0;
100 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4052114.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值