51nod-LCA问题_by_zyz
关于LCA
题目链接:点这里
LCA最简单的思想就是暴力搜,如下:
对于每一组点u,v,求LCA(u,v)
先判断它们是否在同一深度上,不在则暴力将深度靠下的点暴力向上
然后再一同向上
但是对于上面的题一定会T了几个点
所以我们使用倍增
因为对于以上的暴力向上,我们实际上可以一次性向上走很多步,就像一步一步走和跨一大步一样
至于怎么跨一大步呢?
我们需要用到2进制了
因为对于每一个数,我们都可以用2进制表示
那么u到LCA(u,v)是不是也可以表示为2进制呢?
所以我们需要维护一个数组f[i][j]表示i节点向上走2^j次是哪一个节点
并且f[i][j] = f[f[i][j - 1]][j - 1](j == 0时f[i][j] = fa[i])
然后将他们递归到一个深度
先假设depth[u] > depth[v]
所以u要向上走k = depth[u] - depth[v]步
然后又因为k可以分解为2进制
所以你会发现u要向上走的步数从一步一步走变成了在二进制下k的每一位如果是1u = f[u][位数]
然后就是如何走到一处
我们从最大步数开始向下枚举(i)
如果f[u][i] != f[v][i]我们就让u,v分别向上走2 ^ i步
然后LCA(u,v) = f[u][0] = f[v][0]
这道题就解完了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 100;
int n, q;
int dep[maxn];
long long dis[maxn];
int f[maxn][30];
struct Edge{int to,weight;
};
vector<Edge> e[maxn];
void dfs(int u,int fa){f[u][0] = fa;for(int i = 1;i <= 20;i++){f[u][i] = f[f[u][i - 1]][i - 1];}for(int i = e[u].size() - 1;i >= 0;i--){int v = e[u][i].to;int w = e[u][i].weight;if(v == fa)continue;dep[v] = dep[u] + 1;dis[v] = dis[u] + w;dfs(v,u);}
}
int LCA(int u,int v){if(dep[u] < dep[v])swap(u,v);int k = dep[u] - dep[v];for(int i = 20;i >= 0;i--){if((k >> i) & 1){u = f[u][i];}}if(u == v)return u;for(int i = 20;i >= 0;i--){if(f[u][i] != f[v][i]){u = f[u][i];v = f[v][i];}}return f[u][0];
}
int main(){scanf("%d%d",&n,&q);int u, v, w;for(int i = 1;i < n;i++){scanf("%d%d%d",&u,&v,&w);e[u].push_back(Edge{v,w});e[v].push_back(Edge{u,w});}dep[1] = 0;dis[1] = 0;dfs(1,0);for(int i = 1;i <= q;i++){scanf("%d%d",&u,&v);printf("%d\n",dis[u] - 2 * dis[LCA(u,v)] + dis[v]);}return 0;
}
51nod-LCA问题_by_zyz相关推荐
- 51nod 2621 树上距离 (倍增+ LCA 模板)
51nod 2621 树上距离 (倍增+ LCA 模板) 有一棵n个节点的无向树,每条边有一个边权,现在有q次询问,每次询问给出两个点,求这两个点之间的简单路径上的边权和是多少. 输入格式 第1行:两 ...
- [51nod] 1766树上的最远点对 树的直径 树剖LCA+ST表静态查询
题意: 给你一棵带权树,q次查询,每次给出两个区间,[l1,r1][l2,r2][l_1,r_1] [l_2,r_2][l1,r1][l2,r2]从这两个区间中分别选择两个数字,使得这两个点的 ...
- 51nod1743-雪之国度【最小生成树,LCA,并查集】
正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1743 题目大意 nnn个点mmm条边的一张图,每次询问要求找出x,yx, ...
- 51NOD - 1830路径交
题目链接:51NOD - 1830路径交 因为每次是区间询问,所以我们可以类似ST表预处理,或者线段树区间合并去处理. 每次维护节点就是代表所有路径的交集. 现在问题就是两个路径的交怎么求: 两条路径 ...
- 松鼠的新家 51Nod - 3116(点差分)
https://www.51nod.com/Challenge/Problem.html#problemId=3116 题目大意:有一棵n个点的树,给出一长度为n的数组a,依次沿简单路径访问a[1], ...
- 【luogu3398】 仓鼠找sugar [LCA 倍增]
P3398 仓鼠找sugar 长期不学竞赛...导致1mol的低级错误出现 把f数组开为f[N][20] 写错判断 我烂了QAQ我好瘟死于低级错误久久无法判断出来 如果两条路径相交,那么一定有一条路径 ...
- 51nod 1617 奇偶数组
传送门 回来看一眼51nod,发现自己掉到rank4了,赶紧切道题回rank3. 一眼不会做,这种东西应该慢慢找规律吧--然后看到数据范围其实比较小,应该是单次log的,那是不是可以分治啊. #inc ...
- [BZOJ1602] [Usaco2008 Oct] 牧场行走 (LCA)
Description N头牛(2<=n<=1000)别人被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头牛在第i块牧场吃草. 这n块土地被n-1条边连接. 奶牛可以在边上行走, ...
- POJ - 3694 Network tanjar割边+lca
题目链接 思路:跑一边tanjar将所有的割边u->v标记为cut[v]=true,表示u->v这条边为割边.然后记录总的割边数ans,每次从两个询问点暴力往上边在跑直到LCA,如果碰到c ...
- The Shortest Statement CodeForces - 1051F LCA+最短路
太弱了... 一开始看到题感觉是跑一个最小生成树在上边进行LCA就行了,但是发现过不了样例,然后就是就想到了之前做过类似做法的题目,就是非生成树上的边最多只有21条,然后就那些边记录下来,通过每一条边 ...
最新文章
- 2022-2028年中国中空玻璃聚硫密封胶行业市场研究及前瞻分析报告
- 假期只是玩就没意思了!告诉你一个学习麻省理工大学所有课程的好地方
- Ubuntu16.04安装视觉SLAM环境(OpenCV)
- 徒劳的对抗——如何做好极客的老婆(灵感来源于《你就是极客》)
- cefsharp wpf 中文输入问题解决方法
- 操作系统原理第十章:文件系统
- 反恐精英出现服务器消息,cs你已被禁用次服务器 | 手游网游页游攻略大全
- Mac 开发中如何设置 关闭 以及最小化 最大化按钮事件处理
- linux 搜索 空格,如何在Linux中搜索带有空格的模式的文件
- CF446D-DZY Loves Games【高斯消元,矩阵乘法】
- 2021高通AI应用创新大赛-创新赛道-垃圾分类识别 第三次会议研讨
- 基于JAVA语言的selenium测试基础总结
- Matlab高级教程_第一篇:Matlab基础知识提炼_02
- 汉诺塔函数python_Python使用函数模拟“汉诺塔”过程
- DSP28335代码生成——如何使用两个中断
- python如何设置开头注释_小疯谈python:(二)python语言的基本语法元素
- 句法分析(成分句法分析)(依存句法分析)
- CSS3选择器及优先级
- Java 将表格数据导入word文档中
- opencv中mask参数