HDU 2586 How far away ?(LCA模板题)

恰好最近做了强联通,用tarjan比较多,所以就上tarjan的模版来做这题。

看到别人用tarjan求LCA,用到low和dfn两个数组,我们要明白,dfn是用来记录某个点的根,low是记录某个点能获取到最高的根是多少。用tarjan求LCA的时候只需要low即可

代码如下:

#include<bits/stdc++.h>
using namespace std;  
const int maxn = 40005;
  
int head[maxn], to[maxn * 2], nx[maxn * 2], cost[maxn * 2], ppp1; 
int shead[maxn],  sto[maxn], snx[maxn], slca[maxn], sfront[maxn], ppp2;
int n, m;  
int vst[maxn], low[maxn], dis[maxn];  
  
void init()  
{  
    memset(vst, 0, sizeof(vst));  
    memset(dis, 0, sizeof(dis));  
    memset(head, -1, sizeof(head));  
    memset(shead, -1, sizeof(shead));  
    ppp1 = ppp2 = 0;  
}  
  
void add_edge(int u, int v, int val)  
{  
    to[ppp1] = v;
    nx[ppp1] = head[u];
    cost[ppp1] = val;
    head[u] = ppp1++;
}  
  
void s_add_edge(int u,int v)  
{  
    sto[ppp2] = v;
    snx[ppp2] = shead[u];
    sfront[ppp2] = u;
    shead[u] = ppp2++;
}  
  
int Find(int x)  
{  
    if(low[x] == x)
        return x;
    return low[x] = Find(low[x]);
}

void Union(int x, int y)
{
    x = Find(x);
    y = Find(y);
    if(x != y)
        low[y] = x;
}

void tarjan(int u)
{
    vst[u] = 1;
    low[u] = u;
    for(int i = head[u]; ~i; i = nx[i])
    {
        int v = to[i];
        if(!vst[v])
        {
           dis[v] = dis[u] + cost[i];
           tarjan(v);
           Union(u, v);
        }
    }
    for(int i = shead[u]; ~i; i = snx[i])  
    {  
        int v = sto[i];
        if(vst[v])
        {
			int root = Find(v);
        	slca[i] = slca[i ^ 1] = low[root];
        }
    }
}

int main()  
{  
   int T;  
   scanf("%d", &T);  
   while(T--)  
   {  
       init();  
       scanf("%d%d", &n, &m);  
       for(int i = 1; i < n; i++)  
       {  
           int u, v, val;  
           scanf("%d%d%d", &u, &v, &val);  
           add_edge(u, v, val);
           add_edge(v, u, val);
       }  
       for(int i = 0; i < m; i++)  
       {
           int u, v;
           scanf("%d%d", &u, &v);  
           s_add_edge(u, v);  
           s_add_edge(v, u);  
       }
       tarjan(1);
       for(int i = 0; i < m; i++)  
       {  
           int u = sfront[i * 2];
           int v = sto[i * 2];
           int root = slca[i * 2];
           printf("%d\n", dis[u] - dis[root] +  dis[v] - dis[root]);  
       }  
   }  
   return 0;  
}  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值