传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2586

题意:给你N个点,M次询问。1~N-1行输入点与点之间的权值,之后M行输入两个点(a,b)之间的最近距离;

思路:设d[maxn]是当前点到根结点的距离,则答案就是 d[a]-d[lca(a,b)]+d[b]-d[lca(a,b)];

接下来介绍LCA(Least Common Ancestors)

即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。

常见解法一般有三种

这里讲解一种在线算法—倍增

所谓倍增,就是按2的倍数来增大,也就是跳 1,2,4,8,16,321,2,4,8,16,32 …… 不过在这我们不是按从小到大跳,而是从大向小跳,即按……32,16,8,4,2,132,16,8,4,2,1来跳,如果大的跳不过去,再把它调小。


首先我们定义fa[u][j]表示结点u的第2^j祖先 

那么要怎么求出全部的fa数组呢

不难发现fa[u][0]就是u的父亲结点 

这些父亲结点我们可以直接初始化

对于其他结点则有 

f[u][j]=f[ fa[u][j-1] ] [j-1] 

什么意思呢 

u的第2^(j-1)祖先的第2^(j-1)祖先(2^(j-1)+2^(j-1)) 就是u的第2^j祖先


预处理各节点深度+初始化fa数组

void dfs(int x, int fa)
{
h[x] = h[fa] + 1;
f[x][0] = fa;
for(int i = 1; (1 << i) <= h[x]; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for(int i = head[x]; i; i = edges[i].next)
{
if(edges[i].to != fa)
{
d[edges[i].to] = d[x] + edges[i].w;
dfs(edges[i].to, x);
}
}
}

预处理之后怎么求解LCA(u,v)呢 

我么先假定h[u]>h[v] 

则两点深度差 d=h[u]-h[v]

现在我们要做的是把u升到与v同样的深度

while(h[x] > h[y])
x = f[x][lg[h[x] - h[y]] - 1];//因为预处理的log函数是log2(i)+1所以要-1

对于任意一个d 

我们都能将其分解为

所以直接可以得到向上走的指数

而log函数需要预处理

for(int i = 1; i <= maxn; i++)//log2(i)+1
{
if((1 << lg[i - 1]) == i)
lg[i] = lg[i - 1] + 1;
else
lg[i] = lg[i - 1];
}

到相同高度后就可以开始查询LCA了

for(int i = lg[h[x]] - 1; i >= 0; i--)
{
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
}

大体思路就是 

从u和v最远的祖先开始 

如果u的第2^i祖先等于 v的第2^i祖先,就不移动 

否则u和v同时上移2^i个深度 

最后u的父亲一定是u和v的LCA

#include<iostream>
#include<string.h>
#include<cstdio>
using namespace std;
const int maxn = 4e4 + 10;
int n, m;
int tot;
struct node
{
int to;
int next;
int w;
};
node edges[maxn << 1];
int head[maxn];
int lg[maxn];
int h[maxn];
int d[maxn];//当前结点到根结点的深度
int f[maxn][30];//f[i][j] 表示 i 节点的 2^j 级祖先
void add_edges(int u, int v, int w)
{
edges[++tot].to = v;
edges[tot].next = head[u];
edges[tot].w = w;
head[u] = tot;
}
void dfs(int x, int fa)
{
h[x] = h[fa] + 1;
f[x][0] = fa;
for(int i = 1; (1 << i) <= h[x]; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for(int i = head[x]; i; i = edges[i].next)
{
if(edges[i].to != fa)
{
d[edges[i].to] = d[x] + edges[i].w;
dfs(edges[i].to, x);
}
}
}
int lca(int x, int y)
{
if(h[x] < h[y])
swap(x, y);
while(h[x] > h[y])
x = f[x][lg[h[x] - h[y]] - 1];
if(x == y)
return x;
for(int i = lg[h[x]] - 1; i >= 0; i--)
{
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
}
return f[x][0];
}
int main()
{
int T;
scanf("%d", &T);
for(int i = 1; i <= maxn; i++)//log2(i)+1
{
if((1 << lg[i - 1]) == i)
lg[i] = lg[i - 1] + 1;
else
lg[i] = lg[i - 1];
}
while(T--)
{
tot = 0;
memset(head, 0, sizeof(head));
scanf("%d%d", &n, &m);
int i, j, k;
for(int t = 1; t < n; t++)
{
scanf("%d%d%d", &i, &j, &k);
add_edges(i, j, k);
add_edges(j, i, k);
}
dfs(1, -1);
for(int t = 1; t <= m; t++)
{
scanf("%d%d", &i, &j);
cout << d[i] + d[j] - 2 * d[lca(i, j)] << endl;
}
}
}

HDU 2586 How far away ?【LCA模板题】的更多相关文章

  1. hdu 2586 How far away?(LCA模板题+离线tarjan算法)

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  2. HDU - 2586 How far away ?(LCA模板题)

    HDU - 2586 How far away ? Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & ...

  3. HDU 2586——How far away ?——————【LCA模板题】

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. HDU 2602 - Bone Collector - [01背包模板题]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602 Many years ago , in Teddy’s hometown there was a ...

  5. HDU 2544 最短路 【Dijkstra模板题】

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2544 思路:最短路的模板题 Dijkstra 算法是一种类似于贪心的算法,步骤如下: 1.当到一个点时, ...

  6. 【网络流#2】hdu 1533 - 最小费用最大流模板题

    最小费用最大流,即MCMF(Minimum Cost Maximum Flow)问题 嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(Ho ...

  7. hdu 1711 Number Sequence(KMP模板题)

    我的第一道KMP. 把两个数列分别当成KMP算法中的模式串和目标串,这道题就变成了一个KMP算法模板题. #include<stdio.h> #include<string.h> ...

  8. HDU 1874 畅通工程续(模板题——Floyd算法)

    题目: 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多.这让行人很困扰 ...

  9. HDU 1301-Jungle Roads【Kruscal】模板题

    题目链接>>> 题目大意: 给出n个城市,接下来n行每一行对应该城市所能连接的城市的个数,城市的编号以及花费,现在求能连通整个城市所需要的最小花费. 解题分析: 最小生成树模板题,下 ...

  10. 敌兵布阵 HDU - 1166 (树状数组模板题,线段树模板题)

    思路:就是树状数组的模板题,利用的就是单点更新和区间求和是树状数组的强项时间复杂度为m*log(n) 没想到自己以前把这道题当线段树的单点更新刷了. 树状数组: #include<iostrea ...

随机推荐

  1. 更换虚拟机VMware Workstation14和centos7版本及工具

    本博主之前一直沿用的centos是6.7比较老,工作站是10,想要更换一批新版本的工具,并将之前的一些开发环境整理出来移动到该版本上,将其记录在下 一.下载准备 1.下载centos7镜像,选择最小的 ...

  2. C++编程学习(七) 循环结构

    1.continue:循环体中结束本次循环,直接进入下一次循环. 2.break:循环直接结束. 3.在for语句循环体中执行continue语句,程序会转到“表达式3”继续运行. 4.使用多重循环的 ...

  3. python 编写程序输出50以内勾股数,如下图所示,要求每组显示六祖,各组勾股数无重复

    import math n = 0 for a in range(1,49): for b in range(a,49): c = math.ceil(math.sqrt(a**2+b**2)) if ...

  4. python 检测端口是否被占用

    前记   python中有些常用的东西,虽然小,但是非常实用.这里就做个备忘吧. 实例 检测端口是否被占用. ''' -- coding: utf-8 -- import os import sock ...

  5. 11.json

    import json # json反序列化 # json_str = '{"name":"qiyue","age":18}' # stud ...

  6. 【转】ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  7. 类成员之迭代iter

    class B: def __init__(self,name,age): self.name = name self.age = age #创建迭代方法 def __iter__(self): re ...

  8. Java多线程的应用

    一.概述 提到线程不得不提进行.因为线程是进程的一个执行单元.下面对线程和进程分别进行介绍. 1.进程 进程是当前操作系统执行的任务,是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概 ...

  9. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring事务管理接口PlatformTransactionManager、TransactionDefinition和TransactionStatus

    Spring 的事务管理是基于 AOP 实现的,而 AOP 是以方法为单位的.Spring 的事务属性分别为传播行为.隔离级别.只读和超时属性,这些属性提供了事务应用的方法和描述策略. 在 Java ...

  10. Java Web学生信息保存

    Course.javapackage entity; public class Course { private int id; private String num; private String ...