1. 程式人生 > >hdu 2586How far away ? 最近公共祖先LCA離線演算法

hdu 2586How far away ? 最近公共祖先LCA離線演算法

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"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.

題意:n個節點m條詢問,問從x1節點到x2節點的最短距離。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxn 40005
#define LL long long
using namespace std;
struct node{
    int v,w;
};
vector<node>S[maxn];
vector<node>Q[maxn];
int visit[maxn],f[maxn],Rank[maxn],anc[maxn],ans[maxn],dis[maxn];
int n,m;
void init()
{
    for(int i=0;i<=n;i++)
    {
        S[i].clear(),Q[i].clear(),ans[i]=0,anc[i]=0,f[i]=i,Rank[i]=1,dis[i]=0;
    }
    memset(visit,0,sizeof(visit));
}
int Find(int u)
{
    if(f[u]!=u)
        f[u]=Find(f[u]);
    return f[u];
}
void Union(int u,int v)
{
    int f1,f2;
    f1=Find(u),f2=Find(v);
    if(f1!=f2)
    {
        if(Rank[f1]<Rank[f2])
        {
            f[f1]=f2;
            Rank[f2]+=Rank[f1];
        }
        else
        {
            f[f2]=f1;
            Rank[f1]+=Rank[f2];
        }
    }
}
void tarjan(int pos,int flow)
{
    anc[pos]=pos;
    dis[pos]=flow;
    for(int i=0;i<S[pos].size();i++)
    {
        int x=S[pos][i].v;
        if(!visit[x])
        {
            flow+=S[pos][i].w;
            tarjan(x,flow);
            Union(pos,x);
            anc[Find(x)]=pos;
        }
    }
    visit[pos]=1;
    for(int i=0;i<Q[pos].size();i++)
    {
        int x=Q[pos][i].v;
        int z=Q[pos][i].w;
        if(visit[x])
        {
            ans[z]=dis[pos]+dis[x]-2*dis[anc[Find(x)]];
        }
    }
}
int main()
{
    int T;
    cin>>T;
    int in[maxn];
    while(T--)
    {
        cin>>n>>m;
        init();
        memset(in,0,sizeof(in));
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            node tmp;
            cin>>x>>y>>z;
            tmp.v=y,tmp.w=z;
            S[x].push_back(tmp);
            in[y]++;//標記出根節點
            //tmp.v=x,tmp.w=z;
            //S[y].push_back(tmp);
            //in[x]++;
        }
        for(int i=1;i<=m;i++)
        {
            int x,y;
            node tmp;
            cin>>x>>y;
            tmp.v=y,tmp.w=i;
            Q[x].push_back(tmp);
            tmp.v=x,tmp.w=i;
            Q[y].push_back(tmp);
        }
        for(int i=1;i<=n;i++)
        {
            if(in[i]==0)
            {
                //cout<<i<<endl;
                tarjan(i,0);
                break;
            }
        }
        for(int i=1;i<=m;i++)
        {
            cout<<ans[i]<<endl;
        }
    }
}


相關推薦

hdu 2586How far away最近公共祖先LCA離線演算法

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

最近公共祖先LCA:Tarjan演算法

1,並查集+dfs 對整個樹進行深度優先遍歷,並在遍歷的過程中不斷地把一些目前可能查詢到的並且結果相同的節點用並查集合並. 2,分類,使每個結點都落到某個類中,到時候只要執行集合查詢,就可以知道結點的LCA了。 對於一個結點u.類別有: 以u為根的子樹、除類一以外的以f

LCA最近公共祖先離線演算法Tarjan

對於5的每個兒子,LCA,先LCA(1),1沒有兒子,跳過第一個for,然後,visit[1]=true;查詢的vector中(用vector來記錄這個樹和查詢比較好,空間效率比較高),有一組(1,5),可是visit[5]現在仍然是初始值false; 然後,退出1的LCA,回到5的LCA,此時,進行5的第

LCA最近公共祖先離線演算法(Tarjan)和線上演算法(ST)

最近公共祖先簡稱LCA(Lowest Common Ancestors),所謂LCA,是當給定一個有根樹T時,對於任意兩個結點u、v,找到一個離根最遠的結點x,使得x同時是u和v的祖先,x 便是u、

HDU4547 CD操作(最近公共祖先lca,離線Tarjan,有坑點)

Problem Description  在Windows下我們可以通過cmd執行DOS的部分功能,其中CD是一條很有意思的命令,通過CD操作,我們可以改變當前目錄。   這裡我們簡化一下問題,假設只有一個根目錄,CD操作也只有兩種方式:  

[hiho]#1067 : 最近公共祖先·二 離線演算法

描述:(原題地址:http://hihocoder.com/problemset/problem/1067?sid=601284) 給定一顆樹,給出樹根,以及一些查詢pair,要求輸出每條查詢pair的最近公共節點。 保證所有查詢節點都在這棵樹上。 輸入:第一行一個整數N代

最小公共祖先(LCA)離線演算法_Tarjan c++實現

#include <iostream> #include <vector> #include <map> #include <set> using namespace std; struct Node { int val

【C++】最近公共祖先LCA(Tarjan離線算法)&& 洛谷P3379LCA模板

target sizeof add 例題 開始 實現 再看 根節點 strong 1.前言   首先我們介紹的算法是LCA問題中的離線算法-Tarjan算法,該算法采用DFS+並查集,再看此算法之前首先你得知道並查集(盡管我相信你如果知道這個的話肯定是知道並查集的),

筆記:LCA最近公共祖先 Tarjan(離線)算法

否則 二叉樹 tail [] info enter 父親節 自己 初始 LCA最近公共祖先 Tarjan他賤(離線)算法的基本思路及其算法實現 本文是網絡資料整理或部分轉載或部分原創,參考文章如下: https://www.cnblogs.com/JVxie/p/4

[模板]最近公共祖先(LCA)

一段 post 大小 const fin cstring https string print https://www.luogu.org/problemnew/show/P3379 1 #include <bits/stdc++.h> 2 us

最近公共祖先--lca

tchar put def https () iostream max continue lca 模版題 https://www.luogu.org/problemnew/show/P3379 1 #include<algorithm> 2 #inc

最近公共祖先LCA詳細解法

最近公共祖先(LCA)是樹上倍增的一種典型例題。 問題描述:給定一棵具有n個節點的樹,詢問兩個節點x,y的最近的公共祖先。   分析:首先我們想到的是暴力演算法,當然這個演算法妥妥的會TLE掉,所以我們採用倍增優化的方法來進行實現,也就是我們今天介紹的重點。   所謂倍增,就是按2的倍數

最近公共祖先——LCA 總結及其運用

tarjan模板 #include<cstdio> #include<iostream> #include<cstring> #include<algor

LCA最近公共祖先)Tarjan演算法模板

#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; /** 1.dfs 2.

最近公共祖先LCA 模板

程式碼如下: #include<cstdio> #include <iostream> #include <cstring> #include <cstdli

最近公共祖先LCA---線上倍增演算法

  線上求LCA,多次詢問。倍增演算法時間複雜度為。   1、dfs求每個節點所在層數 void dfs(int u,int root,int d) { int i; depth[u]=d; fa[u][0]=root;//初始化 int

最近公共祖先 LCA

一、基本演算法        1、 Tarjan演算法基於深度優先搜尋的框架,對於新搜尋到的一個節點,首先建立有這個節點構成的集合,再對當前節點的每一個子樹進行搜尋,每搜尋完一個子樹,則確定子樹內的L

用於求最近公共祖先(LCA)的 Tarjan演算法–以POJ1986為例(轉)

給定有向無環圖(就是樹,不一定有沒有根),給定點U,V,找出點R,保證點R是U,V的公共祖先,且深度最深;或者理解為R離這兩個點的距離之和最小.如何找出R呢? 最一般的演算法是DFS(DFS本是深度優先搜尋,在這裡姑且把深度優先遍歷也叫做DFS,其實是

[模板] 最近公共祖先/lca

簡介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路徑和b到n的路徑的深度最大的公共點. 定理. 以 \(r\) 為根的樹上的路徑 \((a,b) = (r,a) + (r,b) - 2 * (r,fa(lca))\). (樹上差分) 求法 tarjan 離線演算法, 總時間 \(O(n+

[Tarjan演算法]最近公共祖先(LCA)問題求解

想了一想幾個月前打的用於解LCA的Tarjan貌似棄坑就沒再管它,然後虛擬機器磁碟被我莫名其妙起爆了以後之前打的程式全都打了水漂就想起了被置之不理的Tarjan解LCA問題的板子,索性就把坑填上唄,畢竟我不是挖坑不填的主 明明還有一堆亂七八糟的平衡樹沒填 LC