zoukankan      html  css  js  c++  java
  • HDU 2586 LCA-Tarjan

    还是LCA-tarjan算法,跟POJ 1330做法基本类似,只是这个题目要求输出两个点的最短距离,其实利用LCA的性质,就是 两个点分别到最近公共祖先的距离之和

    一开始本来想用并查集把路径长度给找出来,但是不太好处理,原因是我刚好找到的这个点还没有加入到并查集中,(因为还没回溯上去),如果马上就合并,我还得把父亲传下来,还破坏了原有算法的结构(在孩子这里就进行了并查集合并操作),会产生奇怪的结果。。。

    有个很简便又机智的方法,就是在dfs的过程中 一边记录从rt到下面的点的距离dis,假设 A 和 B 的LCA 是C,那么 我求的其实就是disA-disC+disB-disC,很机智吧

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int N =80000+10;
    int vis[N/2],f[N/2],dis[N/2],ans[N/2];
    int v[N],w[N],nt[N],ft[N/2];
    struct node
    {
        int v,id;
        node(int _v,int _id)
        {
            v=_v;
            id=_id;
        }
    };
    vector<node> Q[N/2];
    int out[211];
    int n,m,tot;
    void init()
    {
        tot=0;
        for (int i=0;i<=n+1;i++){
            ft[i]=-1;
            Q[i].clear();
            f[i]=i;
            dis[i]=0;
            vis[i]=0;
        }
    }
    void add(int x,int y,int c)
    {
        v[tot]=y;
        w[tot]=c;
        nt[tot]=ft[x];
        ft[x]=tot++;
    }
    int findset(int x)
    {
        if (x!=f[x]){
            f[x]=findset(f[x]);
        }
        return f[x];
    }
    int unionset(int a,int b)
    {
        int r1,r2;
        r1=findset(a);
        r2=findset(b);
        if (r1==r2) return r1;
        f[r2]=r1;
        return r1;
    }
    void LCA(int x,int pre)
    {
        ans[x]=x;
        for (int i=ft[x];i!=-1;i=nt[i]){
            int vx=v[i];
            if (vx==pre) continue;
            dis[vx]=dis[x]+w[i];
            LCA(vx,x);
            int rt=unionset(x,vx);
            ans[rt]=x;
        }
        vis[x]=1;
        for (int i=0;i<Q[x].size();i++){
            node tmp=Q[x][i];
            int vx=tmp.v;
            if (vis[vx]){
                out[tmp.id]=dis[x]+dis[vx]-2*dis[ans[findset(vx)]];
            }
        }
    }
    int main()
    {
        int t,a,b,c;
        scanf("%d",&t);
        while (t--)
        {
            scanf("%d%d",&n,&m);
            init();
            for (int i=1;i<n;i++){
                scanf("%d%d%d",&a,&b,&c);
                add(a,b,c);
                add(b,a,c);
            }
            for (int i=0;i<m;i++){
                scanf("%d%d",&a,&b);
                Q[a].push_back(node(b,i));
                Q[b].push_back(node(a,i));
            }
            dis[1]=0;
    
            LCA(1,-1);
            for (int i=0;i<m;i++){
                printf("%d
    ",out[i]);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    开源数据汇集工具
    scrapy定时执行抓取任务
    xpath的常见操作
    ubuntu 安装python mysqldb
    sudo: /etc/sudoers is owned by uid 755, should be 0
    ubuntu 14.04安装mysql数据库
    win7 远程桌面连接centos 6.5
    本地启动spark-shell
    ubuntu 安装 2.10.x版本的scala
    unfolding maps支持中文
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3902879.html
Copyright © 2011-2022 走看看