题目描述 Description

小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力

输入描述 Input Description

第一行一个n,接下来n-1行每一行有三个整数u, v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。

第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u, v 表示两只虫子所在的节点

输出描述 Output Description

一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。

样例输入 Sample Input

3
1 0 1
2 0 1
3
1 0
2 0
1 2

样例输出 Sample Output

1
1
2

数据范围及提示 Data Size & Hint

1<=n<=50000,1<=m<=75000,0<=c<=1000

题解和代码

这道题显然是一道LCA的题目,我们可以跑一遍树上倍增。

#include <iostream>
#include <deque>
#include <vector>
#include <cmath>
using namespace std;
int n, m;
struct edge_type
{
int u, v, c, nextu, nextv;
};
edge_type edge[50005];
const int root = 0;
int hu[50005], hv[50005], fa[50005], fac[50005], deep[50005], f[50005][30], maxdeep = 0, fsum[50005][30];
int maxi;
bool vis[50005];
vector<int> son[50005];
deque<int> q;
void bfs_build_tree(const int root)
{
q.push_back(root);
for (int i = 0; i <= n; ++i)
{
vis[i] = false;
}
vis[root] = true;
deep[root] = 1;
int now;
while (!q.empty())
{
now = q.front();
if (maxdeep < deep[now])
maxdeep = deep[now];
q.pop_front();
int i = hu[now];
while (i)
{
if (!vis[edge[i].v])
{
q.push_back(edge[i].v);
vis[edge[i].v] = true;
fa[edge[i].v] = now;
fac[edge[i].v] = edge[i].c;
son[now].push_back(edge[i].v);
deep[edge[i].v] = deep[now] + 1;
}
i = edge[i].nextu;
}
i = hv[now];
while (i)
{
if (!vis[edge[i].u])
{
q.push_back(edge[i].u);
vis[edge[i].u] = true;
fa[edge[i].u] = now;
fac[edge[i].u] = edge[i].c;
son[now].push_back(edge[i].u);
deep[edge[i].u] = deep[now] + 1;
}
i = edge[i].nextv;
}
}
}
void get_f()
{
maxi = log2(double(maxdeep)-0.5);
for (int j = 0; j < n; ++j)
{
f[j][0] = fa[j];
fsum[j][0] = fac[j];
for (int i = 1; i <= 30; ++i)
fsum[j][i] = f[j][i] = -1;
}
fsum[0][0] = f[0][0] = -1;
for (int i = 1; i <= maxi; ++i)
for (int j = 1; j < n; ++j)
if ((1 << i) < deep[j])
{
f[j][i] = f[f[j][i-1]][i-1];
fsum[j][i] = fsum[j][i-1] + fsum[f[j][i-1]][i-1];
}
}
int g(int x, int y)
{
int ret = 0, a = x, b = y;
while (deep[b] > deep[a])
{
for (int i = maxi; i >= 0; --i)
if (deep[f[b][i]] > deep[a])
{
ret += fsum[b][i];
b = f[b][i];
}
if (deep[fa[b]] == deep[a])
{
ret += fac[b];
b = fa[b];
}
}
while (deep[a] > deep[b])
{
for (int i = maxi; i >= 0; --i)
if (deep[f[a][i]] > deep[b])
{
ret += fsum[a][i];
a = f[a][i];
}
if (deep[fa[a]] == deep[b])
{
ret += fac[a];
a = fa[a];
}
}
while (a != b)
{
for (int i = maxi; i >= 0; --i)
if (f[a][i] != f[b][i])
{
ret += (fsum[a][i] + fsum[b][i]);
a = f[a][i];
b = f[b][i];
}
if (fa[a] == fa[b])
{
ret += (fac[a] + fac[b]);
a = fa[a];
b = fa[b];
}
}
return ret;
}
int main()
{
cin >> n;
int u, v, c;
for (int i = 1; i < n; ++i)
{
cin >> u >> v >> c;
edge[i].u = u;
edge[i].v = v;
edge[i].c = c;
edge[i].nextu = hu[u];
edge[i].nextv = hv[v];
hu[u] = i;
hv[v] = i;
}
bfs_build_tree(root);
get_f();
cin >> m;
int a, b;
for (int i = 0; i < m; ++i)
{
cin >> a >> b;
cout << g(a, b) << endl;
}
}

Codevs 2370 小机房的树 LCA 树上倍增的更多相关文章

  1. CodeVs.2370 小机房的树 ( LCA 倍增 最近公共祖先)

    CodeVs.2370 小机房的树 ( LCA 倍增 最近公共祖先) 题意分析 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天, ...

  2. codevs 2370 小机房的树(LCA)

    过了这么长的时间终于开始看LCA了... 有一次训练题卡在LCA当时不会...拖了好久好久...其实现在还是不会... 只会tarjan... 传送门 板子题咯 tarjan的算法就是基于先序遍历的顺 ...

  3. LCA(倍增在线算法) codevs 2370 小机房的树

    codevs 2370 小机房的树 时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点, ...

  4. Codevs 2370 小机房的树

    2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为 ...

  5. codevs——2370 小机房的树

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 小机房有棵焕狗种的树,树上有N个 ...

  6. 放一道比较基础的LCA 的题目把 :CODEVS 2370 小机房的树

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  7. 【codevs2370】小机房的树 LCA 倍增

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0 ...

  8. [CodeVS2370] 小机房的树 (LCA, 树链剖分, LCT)

    Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花 ...

  9. [codevs2370]小机房的树<LCA>

    题目链接:http://codevs.cn/problem/2370/ 这题我还是做了比较久了,因为有人告诉我这是用tarjan离线做 好吧算我是蒟蒻,真心不懂tarjan怎么做,最后还是用倍增做的 ...

随机推荐

  1. python 3.x urllib学习

    urllib.request import urllib.request as ur url='http://ie.icoa.cn' user_agent = 'Mozilla/4.0 (compat ...

  2. Lua 读表代码,自动生成字段名字

    表格格式为 INT STRING INT INT INT INT INT Id Desc Type SceneId OpenId MaxPliesp ClearancePlies 第1关 - 第2关 ...

  3. 解决SprngMVC中ResponseBody注解中文乱码

    配置文件前面加入如下结构,版本号3.2.5 <bean class="org.springframework.web.servlet.mvc.method.annotation.Req ...

  4. OneThink开发框架

    OneThink是一个开源的内容管理框架,基于最新的ThinkPHP3.2版本开发,提供更方便.更安全的WEB应用开发体验,采用了全新的架构设计和命名空间机制,融合了模块化.驱动化和插件化的设计理念于 ...

  5. MYSQL外键(Foreign Key)的使用

    在MySQL 3.23.44版本后,InnoDB引擎类型的表支持了外键约束.外键的使用条件:1.两个表必须是InnoDB表,MyISAM表暂时不支持外键(据说以后的版本有可能支持,但至少目前不支持): ...

  6. SpringBoot配置属性之DataSource

    https://segmentfault.com/a/1190000004316491

  7. BZOJ4712 : 洪水

    首先不难列出DP方程: $dp[x]=\min(w[x],h[x])$ $h[x]=\sum dp[son]$ 当$w[x]$增加时,显然$dp[x]$不会减少,那么我们求出$dp[x]$的增量$de ...

  8. 关于过拟合、局部最小值、以及Poor Generalization的思考

    Poor Generalization 这可能是实际中遇到的最多问题. 比如FC网络为什么效果比CNN差那么多啊,是不是陷入局部最小值啊?是不是过拟合啊?是不是欠拟合啊? 在操场跑步的时候,又从SVM ...

  9. PRML读书后记(一): 拟合学习

    高斯分布·拟合 1.1 优美的高斯分布 中心极限定理[P79]证明均匀分布和二项分布在数据量 $N\rightarrow \infty$ 时,都会演化近似为高斯分布. 作为最晚发现的概率分布,可以假设 ...

  10. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...