HDU 2586 How far away ? (LCA)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
LCA模版题。
RMQ+LCA:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 6 using namespace std; 7 const int MAXN = 4e4 + 100; 8 typedef pair<int , int>P; 9 vector <P> G[MAXN]; 10 int dep[MAXN] , dis[MAXN] , par[MAXN][20] , ok[MAXN]; 11 12 void init(int n) { 13 for(int i = 1 ; i <= n ; i++) { 14 G[i].clear(); 15 ok[i] = 0; 16 } 17 } 18 19 void dfs(int root) { 20 for(int i = 0 ; i < G[root].size() ; i++) { 21 dis[G[root][i].first] = dis[root] + G[root][i].second; 22 dfs(G[root][i].first); 23 } 24 } 25 26 void dfs2(int u , int p , int d) { 27 dep[u] = d; 28 par[u][0] = p; 29 for(int i = 0 ; i < G[u].size() ; i++) { 30 dfs2(G[u][i].first , u , d + 1); 31 } 32 } 33 34 int lca(int u , int v) { 35 if(dep[u] < dep[v]) { 36 swap(u , v); 37 } 38 for(int k = 0 ; k < 16 ; k++) { 39 if((dep[u] - dep[v]) >> k & 1) { 40 u = par[u][k]; 41 } 42 } 43 if(u == v) 44 return u; 45 for(int k = 15 ; k >= 0 ; k--) { 46 if(par[u][k] != par[v][k]) { 47 u = par[u][k]; 48 v = par[v][k]; 49 } 50 } 51 return par[u][0]; 52 } 53 54 int main() 55 { 56 int n , m , q , v , u , d , root , t; 57 char op[10]; 58 scanf("%d" , &t); 59 while(t--) { 60 scanf("%d %d" , &n , &m); 61 init(n); 62 root = (n + 1) * n / 2; 63 for(int i = 0 ; i < n - 1 ; i++) { 64 scanf("%d %d %d" , &u , &v , &d); 65 G[u].push_back(P(v , d)); 66 if(!ok[v]) { 67 root -= v; 68 ok[v] = 1; 69 } 70 } 71 dfs2(root , -1 , 0); 72 dis[root] = 0; 73 for(int k = 0 ; k < 16 ; k++) { 74 for(int i = 1 ; i <= n ; i++) { 75 if(par[i][k] <= 0) { 76 par[i][k + 1] = 0; 77 } 78 else { 79 par[i][k + 1] = par[par[i][k]][k]; 80 } 81 } 82 } 83 dfs(root); 84 for(int i = 0 ; i < m ; i++) { 85 scanf("%d %d" , &u , &v); 86 printf("%d\n" , dis[u] + dis[v] - 2 * dis[lca(u , v)]); 87 } 88 } 89 }
树链剖分的LCA:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int MAXN = 5e4 + 10; 6 struct data { 7 int to , next , cost; 8 }edge[MAXN << 1]; 9 int head[MAXN] , cnt; 10 int par[MAXN] , dep[MAXN] , top[MAXN] , id[MAXN] , dis[MAXN] , size[MAXN] , son[MAXN]; 11 12 void init() { 13 memset(head , -1 , sizeof(head)); 14 cnt = 0; 15 } 16 17 inline void add(int u , int v , int cost) { 18 edge[cnt].to = v; 19 edge[cnt].next = head[u]; 20 edge[cnt].cost = cost; 21 head[u] = cnt++; 22 } 23 //求size , par , son , dep 24 void dfs_1(int u , int p , int d) { 25 par[u] = p , size[u] = 1 , son[u] = u , dep[u] = d; 26 for(int i = head[u] ; ~i ; i = edge[i].next) { 27 int v = edge[i].to; 28 if(v == p) 29 continue; 30 dis[v] = dis[u] + edge[i].cost; //离根的距离 31 dfs_1(v , u , d + 1); 32 if(size[v] > size[son[u]]) //取重儿子 33 son[u] = v; 34 size[u] += size[v]; 35 } 36 } 37 //求top , id 38 void dfs_2(int u , int p , int t) { //p为父节点 t为链的祖先 39 top[u] = t; //链的祖先 40 id[u] = ++cnt; //点的顺序 41 if(son[u] != u) //重儿子优先 42 dfs_2(son[u] , u , t); 43 for(int i = head[u] ; ~i ; i = edge[i].next) { 44 int v = edge[i].to; 45 if(v == p || v == son[u]) 46 continue; 47 dfs_2(v , u , v); //树链重新开始 48 } 49 } 50 //树链剖分求lca的复杂度是(nlognlogn),建议用RMQ求lca 51 int lca(int u , int v) { 52 int fu = top[u] , fv = top[v]; 53 while(top[u] != top[v]) { //链是否相同,不同就循环 54 if(dep[fu] < dep[fv]) { //比较两个链的深度 55 v = par[fv]; 56 fv = top[fv]; 57 } 58 else { 59 u = par[fu]; 60 fu = top[u]; 61 } 62 } 63 if(dep[u] >= dep[v]) //在相同的链上 64 return v; 65 return u; 66 } 67 68 int main() 69 { 70 int n , q , u , v , cost , x , y , z , t; 71 scanf("%d" , &t); 72 while(t--) { 73 scanf("%d %d" , &n , &q); 74 init(); 75 for(int i = 1 ; i < n ; ++i) { 76 scanf("%d %d %d" , &u , &v , &cost); 77 add(u , v , cost); 78 add(v , u , cost); 79 } 80 cnt = 0; 81 dfs_1(1 , 1 , 0); 82 dfs_2(1 , 1 , 1); 83 while(q--) { 84 scanf("%d %d" , &x , &y); 85 int res = (dis[x] + dis[y] - 2 * dis[lca(x , y)]); 86 printf("%d\n" , res); 87 } 88 } 89 }