传送门: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. cf 763A. Timofey and a tree

    呵呵呵,直接判断是不是一个点连起来所有的特殊边(连接2不同颜色的点的边) (一开始还想各种各样奇怪的dfs...垃圾) #include<bits/stdc++.h> #define LL ...

  2. 055-for循环中break的使用

    <?php ;;$x++){ //省略表达式2的for循环将是无限循环 echo "$x<br />"; ){ break; //使用if语句控制退出无限循环 } ...

  3. StackExchange.Redis.DLL 操作redis加强版

    直接引用StackExchange.Redis.dll这一个dll来操作redis App.config配置 <?xml version="1.0" encoding=&qu ...

  4. CentOS 7 下oracle 11G R2 ADG 搭建

    本文记录ADG搭建操作步骤,首先在虚拟机CentOS中安装并配置好oracle 11g R2(具体安装步骤在我的另一篇博客中),然后拷贝一份虚拟机,修改新虚拟机的主机名和ip配置,这时候主库和备库是一 ...

  5. slave_net_timeout, MASTER_HEARTBEAT_PERIOD, MASTER_CONNECT_RETRY,以及 MASTER_RETRY_COUNT设置和查看

    在主从复制中,有几个参数是非常重要的,包括slave_net_timeout, MASTER_HEARTBEAT_PERIOD, MASTER_CONNECT_RETRY,以及 MASTER_RETR ...

  6. UVA - 1149 Bin Packing(装箱)(贪心)

    题意:给定N(N<=10^5)个物品的重量Li,背包的容量M,同时要求每个背包最多装两个物品.求至少要多少个背包才能装下所有的物品. 分析:先排序,从最重的开始装,如果重量小于M,则如果能装一个 ...

  7. POJ 1423:Big Number 求N的阶乘的长度 斯特林公式

    Big Number Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 27027   Accepted: 8626 Descr ...

  8. Promise 练习

    import { ModelClass } from "engine/injector/Injector"; import { Inject } from "core/i ...

  9. android——TextView默认文字开发时显示运行时隐藏

    根布局添加属性: xmlns:tools="http://schemas.android.com/tools" textview添加属性: tools:text="默认文 ...

  10. HTTP协议、时间戳

    1.什么是HTTP协议 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数据通信的 ...