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\n",out[i]);
        }
    }
    return 0;
}

  

HDU 2586 LCA-Tarjan

时间: 2024-10-26 17:12:36

HDU 2586 LCA-Tarjan的相关文章

hdu 2586 LCA模板题(离线算法)

http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B&quo

HDU 2586 LCA离线算法 tarjan算法

LCA tarjan算法模板题 题意:给一个无根树,有q个询问,每个询问两个点,问两点的距离. 用tarjan离线算法算出每个询问的两点的最近公共祖先 ans[i]=dis[x[i]]+dis[y[i]]-2*dis[z[i]]; //  x[i],y[i]分别存储每次询问的两点,z[i]存储这两点的最近公共祖先 #include "stdio.h" #include "string.h" int tot,n,m; int f[40010],x[40010],y[4

HDU 2586 LCA模板题

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:在一个无向树上,求一条链权和. 解题思路: 0 | 1 /   \ 2      3 设dist[i]为i到根0的链和,求法(Dfs过程中dist[v]=dist[u]+e[i].w) 对于树中任意两点形成的链,可以通过LCA最近公共祖先剖分. 比如2->3,就可以经过LCA点1:  2->1->3 链和=dist[u]+dist[v]-2*dist[LCA[u,v]] (

hdu 2586(Tarjan 离线算法)

How far away ?                                                                             Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                                                            

HDU 2586 LCA

LCA模板题. DFS记录好,到根结点的距离. #include <bits/stdc++.h> using namespace std; const int maxn = 40000+5; const int logmaxn = 20; struct Edge { int to,w; }; std::vector<Edge> G[maxn]; int f[maxn],dis[maxn],deep[maxn],p[maxn][20],n; struct LCA { int n; i

hdu 2586(LCA+并查集)

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6734    Accepted Submission(s): 2498 Problem Description There are n houses in the village and some bidirectional roads connecting

HDU 2586 LCA转RMQ

点击打开链接 题意:就是问两个节点间的距离 思路:又切了一道模版水题,不解释了,看不懂变量含义的可以看我写的这篇,解释的比较详细ZOJ 3195 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef

HDU 2586 How far away ? (LCA最近公共祖先)

题目地址:HDU 2586 LCA第一发. 纯模板题. 偷懒用的vector,结果一直爆栈.把G++改成C++就过了.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <se

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

hdu 2586 How far away ?倍增LCA

hdu 2586 How far away ?倍增LCA 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2586 思路: 针对询问次数多的时候,采取倍增求取LCA,同时跟新距离数组 因为 \(2^{16} > 40000\) 所以所以表示祖先的数组dp[][]第二维取到16即可 就这道题来说,与比较tarjan比较,稍快一点 代码: #include <iostream> #include <algorithm> #includ