zoukankan      html  css  js  c++  java
  • 【HDU2586】How far away?-LCA算法模板题

    题目大意:给定一棵有N个节点的树,每条边都有边权。有M个询问,对于每个询问,求出它给出的两点之间路径上的边权之和。

    做法:本题是一道LCA(最近公共祖先)算法的模板题,网上也比较容易查到资料。用dis[i]表示i号节点到树根的距离,那么对于询问(i,j),答案显然是dis[i]+dis[j]-2*dis[lca(i,j)]。本人使用的是Tarjan离线算法,也就是先存下所有询问,再进行求解,那么我们只要在Tarjan算法的遍历过程中求出每个点的dis就可以了。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int t,n,m,a,b,c,tot,first[40010],firstq[40010],fa[40010];
    int lca[210],f[40010],qa[210],qb[210];
    long long dis[40010];
    bool vis[40010];
    struct edge {int v,d,next;} e[80010],q[410];
    
    void insert(int x,int y,int d)
    {
      e[++tot].v=y;
      e[tot].d=d;
      e[tot].next=first[x];
      first[x]=tot;
    }
    
    void insertq(int x,int y,int d)
    {
      q[++tot].v=y;
      q[tot].d=d;
      q[tot].next=firstq[x];
      firstq[x]=tot;
    }
    
    int find(int x)
    {
      int r=x,i=x,j;
      while(f[r]!=r) r=f[r];
      while(i!=r)
      {
        j=f[i];
    	f[i]=r;
    	i=j;
      }
      return r;
    }
    
    void merge(int a,int b)
    {
      int x=find(a),y=find(b);
      f[x]=y;
    }
    
    void tarjan(int v)
    {
      f[v]=v;
      for(int i=first[v];i>0;i=e[i].next)
        if (e[i].v!=fa[v])
    	{
    	  fa[e[i].v]=v;
    	  dis[e[i].v]=dis[v]+e[i].d;
    	  tarjan(e[i].v);
    	}
      for(int i=firstq[v];i>0;i=q[i].next)
        if (vis[q[i].v]||v==q[i].v) lca[q[i].d]=find(q[i].v);
      vis[v]=1;
      merge(v,fa[v]);
    }
    
    int main()
    {
      scanf("%d",&t);
      while(t>0)
      {
        scanf("%d%d",&n,&m);
    	memset(first,0,sizeof(first));
    	memset(firstq,0,sizeof(firstq));
    	memset(vis,0,sizeof(vis));
    	dis[1]=fa[1]=tot=0;
    	for(int i=1;i<n;i++)
    	{
    	  scanf("%d%d%d",&a,&b,&c);
    	  insert(a,b,c);insert(b,a,c);
    	}
    	tot=0;
    	for(int i=1;i<=m;i++)
    	{
    	  scanf("%d%d",&a,&b);
    	  insertq(a,b,i);insertq(b,a,i);
    	  qa[i]=a;qb[i]=b;
    	}
    	for(int i=1;i<=n;i++) f[i]=i;
    	tarjan(1);
    	for(int i=1;i<=m;i++)
    	  printf("%lld
    ",dis[qa[i]]+dis[qb[i]]-2*dis[lca[i]]);
        t--;
      }
      
      return 0;
    }
    


  • 相关阅读:
    Palindrome Linked List 解答
    Word Break II 解答
    Array vs Linked List
    Reverse Linked List II 解答
    Calculate Number Of Islands And Lakes 解答
    Sqrt(x) 解答
    Find Median from Data Stream 解答
    Majority Element II 解答
    Binary Search Tree DFS Template
    188. Best Time to Buy and Sell Stock IV
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793971.html
Copyright © 2011-2022 走看看