LCA 四种解法之一: 倍增 以及例题
hdu-2586 http://acm.hdu.edu.cn/showproblem.php?pid=2586
//题意:一村庄中有n栋房屋, 两房屋之间只有一条路径, 且村庄是联通的。问m次查询两房屋之间的距离,输出每次查询的答案。n(2 <= n <= 40000) m(1 <= m <= 200)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int MAXN = 4e4+5; 7 8 struct node {// 链式向前星 具体原理见博客https://blog.csdn.net/acdreamers/article/details/16902023 9 int u, v, w, next; 10 } edge[2*MAXN]; 11 12 int n, m; 13 int num = 1;// 结点的编号 14 int head[2*MAXN];// 用来映射某值的结点编号 15 int deep[MAXN];// 某点的深度(树) 16 int f[MAXN][21];// f[i][j] 表示i的第2^j祖先 17 int g[MAXN];// 存某点到树根的距离 18 19 void add_edge(int x, int y, int z) {// 建树 20 edge[num].u = x; 21 edge[num].v = y; 22 edge[num].w = z; 23 edge[num].next = head[x]; 24 head[x] = num++; 25 } 26 27 void dfs(int cur) {// 算出每一结点的父亲结点编号、深度、和到树根的距离 28 for(int i = head[cur]; i != -1; i = edge[i].next) { 29 if(deep[edge[i].v] == 0) { 30 deep[edge[i].v] = deep[cur] + 1; 31 f[edge[i].v][0] = cur; 32 g[edge[i].v] = g[cur] + edge[i].w; 33 dfs(edge[i].v); 34 } 35 } 36 } 37 38 void PRE() {// 倍增求f[i][j] 39 for(int j = 1; j <= 19; ++j) { 40 for(int i = 1; i <= n; ++i) { 41 f[i][j] = f[f[i][j-1]][j-1]; 42 } 43 } 44 } 45 46 int LCA(int x, int y) {// 倍增思想 47 if(deep[x] < deep[y]) swap(x, y); 48 for(int i = 19; i >= 0; --i) { 49 if(deep[f[x][i]] >= deep[y]) { 50 x = f[x][i]; 51 } 52 } 53 if(x == y) return x; 54 for(int i = 19; i >= 0; --i) { 55 if(f[x][i] != f[y][i]) { 56 x = f[x][i]; 57 y = f[y][i]; 58 } 59 } 60 return f[x][0]; 61 } 62 63 int main() { 64 int T; 65 scanf("%d", &T); 66 while(T--) { 67 memset(head, -1, sizeof(head)); 68 memset(deep, 0, sizeof(deep)); 69 memset(f, 0, sizeof(f)); 70 memset(g, 0, sizeof(g)); 71 72 scanf("%d%d", &n, &m); 73 int s, e, v; 74 for(int i = 0; i != n-1; ++i) { 75 scanf("%d%d%d", &s, &e, &v); 76 add_edge(s, e, v); 77 add_edge(e, s, v); 78 } 79 deep[1] = 1; 80 dfs(1); 81 PRE(); 82 for(int i = 0; i != m; ++i) { 83 scanf("%d%d", &s, &e); 84 printf("%d\n", g[s]+g[e]-2*g[LCA(s, e)]);// 画图即可理解 85 } 86 } 87 return 0; 88 }
//poj-1986 和上面一题一模一样,没有任何修改。
// 这题输入很奇葩,(我用)用scanf就是wa,然后学了下别人的输入就ac了,很奇怪😵。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int MAXN = 1e5+5; 7 inline int read() { 8 char c = getchar(); int x = 0, f = 1; 9 while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } 10 while(c >= '0' && c <= '9') { x = x*10 + c - '0'; c = getchar(); } 11 return x*f; 12 } 13 // 这中间代码和上面一题一模一样。。。 主函数里面其实也是。输入很奇葩,改成这样就对了。 14 int main() { 15 n = read(), m = read(); 16 memset(head, -1, sizeof(head)); 17 memset(f, 0, sizeof(f)); 18 memset(g, 0, sizeof(g)); 19 memset(deep, 0, sizeof(deep)); 20 21 int s, e, v; 22 for(int i = 0; i != m; ++i) { 23 s = read(), e = read(), v = read(); 24 add_edge(s, e, v); 25 add_edge(e, s, v); 26 } 27 deep[1] = 1; 28 dfs(1); 29 PRE(); 30 m = read(); 31 for(int i = 0; i != m; ++i) { 32 s = read(), e = read(); 33 printf("%d\n", g[s]+g[e]-2*g[LCA(s, e)]); 34 } 35 return 0; 36 }

浙公网安备 33010602011771号