传送门: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. 每天一点点之 uni-app 框架开发 - 页面滚动到指定位置

    项目需求:在页面中,不管位于何处,点击评论按钮页面滚动到对应到位置 实现思路如下: uni.createSelectorQuery().select(".comment").bou ...

  2. sourceTree 生成公钥和私钥 然后拉项目代码

    第一步 用sourceTree生成公钥pub和私钥文件ppk    打开sourceTree -> 工具 -> 创建或导入ssh密钥 -> 点击generate -> 上面会显 ...

  3. 微服务框架中springboot启动的一个问题

    微服务中,采用的是springboot构建单个项目,其中一个项目user启动过程中总是启动补起来,相关的地方都没有错,始终启动不起来,而且要命的是控制台不打印日志,日志级别是debug级别的,但是打印 ...

  4. 深入浅出KNN算法

    概述 K最近邻(kNN,k-NearestNeighbor)分类算法 所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表. kNN算法的核心思想是如果一个样本在特征 ...

  5. ubuntu12.04 安装完XRDP显示空白桌面

    先放链接:http://c-nergy.be/blog/?p=3518 在ubuntu软件中心搜索:fallback session,安装gnome-session-fallback: 在主文件夹(h ...

  6. JAVA - SpringBoot项目引用MyBatis操作数据库

    JAVA - SpringBoot项目引用MyBatis操作数据库 1. 创建SpringBoot项目,参考:https://www.cnblogs.com/1285026182YUAN/p/1232 ...

  7. 如何有效避免Essay写作抄袭

    每到学期末的时候,各种考试,论文以及作业数不胜数,压得留学党们快要喘不过气了.我想比起写论文,同学们更操心的问题应该是:Plagiarism.要知道在国外Plagiarism的这种行为在学术中是零容忍 ...

  8. VM ESXi虚拟化使用学习笔记

    由于疫情原因,没有条件介绍安装部分的内容,也没有安装部分内容的相关截图,所以安装部分可以选择网上资料.但是只要熟练安装CentOS系统的,基本安装ESXi一看就会,设置主机地址方面有一定图形化界面,比 ...

  9. nosql的介绍以及和关系型数据库的区别

    一直对非关系型数据库和关系型数据库的了解感觉不太深入,在网上收集了一些关于sql和nosql的区别和优缺点分享给大家. Nosql介绍 Nosql的全称是Not Only Sql,这个概念早起就有人提 ...

  10. tensorflow--保存加载模型

    s=mnist.train.next_batch(batch_size)print(xs.shape)print(ys.shape) # #从集合中取全部变量# tf.get_collection() ...