1. 程式人生 > >zoj3195(lca / RMQ離線)

zoj3195(lca / RMQ離線)

tarjan i++ swa nbsp max namespace show style closed

題目鏈接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3195

題意: 給出一棵 n 個節點的帶邊權的樹, 有 q 組形如 x, y, z 的詢問, 輸出 x, y, z之間的最短路徑.

思路: 在紙上畫下不難發現 x, y, z之間的最短路徑就是 x, y, z 兩兩之間的最短路徑和的一半.

我們可以通過 lca 模板求出 x, y, z 兩兩之間的最短路徑, 然後再算下 x, y, z三點之間的最短路徑即可.

這題應該是用 RMQ 在線比較好寫一點, 用 tarjan 的話記錄路徑有點麻煩.

代碼:

技術分享
 1
#include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 using namespace std; 6 7 const int MAXN = 5e4 + 10; 8 struct node{ 9 int v, w, next; 10 }edge[MAXN << 1]; 11 12 int dp[MAXN << 1][30]; 13 int ver[MAXN << 1], deep[MAXN << 1
], first[MAXN]; 14 int dis[MAXN], head[MAXN], vis[MAXN], indx, ip; 15 16 inline void init(void){ 17 memset(vis, 0, sizeof(vis)); 18 memset(head, -1, sizeof(head)); 19 indx = 0; 20 ip = 0; 21 } 22 23 void addedge(int u, int v, int w){ 24 edge[ip].v = v; 25 edge[ip].w = w; 26 edge[ip].next = head[u];
27 head[u] = ip++; 28 } 29 30 void dfs(int u, int h){ 31 vis[u] = 1; 32 ver[++indx] = u; 33 deep[indx] = h; 34 first[u] = indx; 35 for(int i = head[u]; i != -1; i = edge[i].next){ 36 int v = edge[i].v; 37 if(!vis[v]){ 38 dis[v] = dis[u] + edge[i].w; 39 dfs(v, h + 1); 40 ver[++indx] = u; 41 deep[indx] = h; 42 } 43 } 44 } 45 46 void ST(int n){ 47 for(int i = 1; i <= n; i++){ 48 dp[i][0] = i; 49 } 50 for(int j = 1; (1 << j) <= n; j++){ 51 for(int i = 1; i + (1 << j) - 1 <= n; i++){ 52 int x = dp[i][j - 1], y = dp[i + (1 << (j - 1))][j - 1]; 53 dp[i][j] = deep[x] < deep[y] ? x : y; 54 } 55 } 56 } 57 58 int RMQ(int l, int r){ 59 int len = log2(r - l + 1); 60 int x = dp[l][len], y = dp[r - (1 << len) + 1][len]; 61 return deep[x] < deep[y] ? x : y; 62 } 63 64 int LCA(int x, int y){ 65 int l = first[x], r = first[y]; 66 if(l > r) swap(l, r); 67 int pos = RMQ(l, r); 68 return ver[pos]; 69 } 70 71 int main(void){ 72 bool flag = false; 73 int n, q, x, y, z; 74 while(~scanf("%d", &n)){ 75 if(flag) puts(""); 76 flag = true; 77 init(); 78 for(int i = 1; i < n; i++){ 79 scanf("%d%d%d", &x, &y, &z); 80 addedge(x, y, z); 81 addedge(y, x, z); 82 } 83 dis[1] = 0; 84 dfs(1, 1); 85 ST(2 * n - 1); 86 scanf("%d", &q); 87 while(q--){ 88 scanf("%d%d%d", &x, &y, &z); 89 int lca1 = LCA(x, y); 90 int lca2 = LCA(x, z); 91 int lca3 = LCA(y, z); 92 int sol1 = dis[x] + dis[y] - 2 * dis[lca1]; 93 int sol2 = dis[x] + dis[z] - 2 * dis[lca2]; 94 int sol3 = dis[y] + dis[z] - 2 * dis[lca3]; 95 printf("%d\n", (sol1 + sol2 + sol3) >> 1); 96 } 97 } 98 return 0; 99 }
View Code

zoj3195(lca / RMQ離線)