1. 程式人生 > >Connections between cities 【HDU - 2874】【線上LCA演算法】

Connections between cities 【HDU - 2874】【線上LCA演算法】

題目連結


  昨天剛學了線上LCA,今天就來硬剛這道題還是花了一整天的時間,不過對於LCA卻有了更多的理解,這道題在講述不同根的做法上尤其是很好的。

  題目告訴我們有N個節點和M條邊,以及C次詢問,每次查詢的是【L、R】這兩個節點間的距離,還是算得上簡單明瞭的告訴了我們得去用最近公共祖先來做的。


  對於LCA,畢竟是初學,還是有些地方容易寫出BUG,譬如說這道題,我一開始想把節點放進dfs()中處理,但是這樣又如何處理不同根的節點呢?顯然是不行的,然後我就換了些許思路,再利用個新的陣列去存是否在同一個根裡,然後在用root[][]去判斷其向上2^J時候能到達的父節點是哪個。

  還有,一開始沒想到該如何去處理在同一棵樹裡的預處理問題(就是預處理算出其向上2^x能到達的父節點),然後,我們用一個vis[]來避免同一棵樹上的節點被多次處理,既然已經在樹上,就說明不會再連線到其他樹上,如果能連線,說明dfs()還能走,所以我們如此處理樹的問題。

  還有一個最氣的就是初始化了,鏈式前向星的head[]陣列是需要初始化的!!!


剩下的坑點就沒什麼了,這道題還莫名良心的沒有卡long long,發現竟然有int也能過的discuss。

寫的比較淳樸,第一次嘛:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define INF 0x3f3f3f3f3f3f
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=10005;
int N, M, C, father[maxN], root[maxN][30], depth[maxN], head[maxN<<1], cnt;
bool vis[maxN];
ll dis[maxN];
void init()
{
    for(int i=1; i<=N; i++) { father[i]=i; dis[i]=0; depth[i]=0; }
    cnt=0;
    memset(root, -1, sizeof(root));
    memset(vis, false, sizeof(vis));
    memset(head, -1, sizeof(head));
}
struct Eddge
{
    int next, to, val;
    Eddge(int a=-1, int b=0, int c=0):next(a), to(b), val(c) {}
}edge[maxN<<1];
void addEddge(int u, int v, int val)
{
    edge[cnt] = Eddge(head[u], v, val);
    head[u] = cnt++;
}
int fid(int x) { return x==father[x]?x:(father[x]=fid(father[x])); }
void mix(int x, int y)
{
    int u=fid(x), v=fid(y);
    if(u != v) father[u] = v;
}
void dfs(int u, int pre)
{
    vis[u] = true;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to, cost=edge[i].val;
        if(v == pre || vis[v]) continue;
        depth[v] = depth[u] + 1;
        dis[v] = dis[u] + cost;
        root[v][0] = u;
        dfs(v, u);
    }
}
void pre_did()
{
    for(int i=1; i<=N; i++)
    {
        if(!vis[i]) dfs(i, -1);
    }
    for(int j=0; (1<<(j+1))<N; j++)
    {
        for(int i=1; i<=N; i++)
        {
            if(root[i][j] < 0) root[i][j+1] = -1;
            else root[i][j+1] = root[root[i][j]][j];
        }
    }
}
int LCA(int u, int v)
{
    if(depth[u] > depth[v]) swap(u, v);
    int det_high = depth[v] - depth[u];
    for(int i=(int)log2(det_high); i>=0; i--)
    {
        if( (1<<i) & det_high ) v = root[v][i];
    }
    if(u == v) return u;
    for(int i=15; i>=0; i--)
    {
        if(root[u][i] != root[v][i])
        {
            u = root[u][i];
            v = root[v][i];
        }
    }
    return root[u][0];
}
int main()
{
    while(scanf("%d%d%d", &N, &M, &C)!=EOF)
    {
        init();
        for(int i=1; i<=M; i++)
        {
            int e1, e2, e3;
            scanf("%d%d%d", &e1, &e2, &e3);
            addEddge(e1, e2, e3);
            addEddge(e2, e1, e3);
            mix(e1, e2);
        }
        pre_did();
        for(int i=1; i<=C; i++)
        {
            int e1, e2;
            scanf("%d%d", &e1, &e2);
            if(fid(e1) != fid(e2)) printf("Not connected\n");
            else printf("%lld\n", dis[e1] + dis[e2] - 2*dis[LCA(e1, e2)]);
        }
    }
    return 0;
}