Connections between cities 【HDU - 2874】【線上LCA演算法】
阿新 • • 發佈:2018-11-20
題目連結
昨天剛學了線上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; }