lca最近公共祖先(st表/倍增)
大体思路
1.求出每个元素在树中的深度
2.用st表预处理的方法处理出f[i][j],f[i][j]表示元素i上方第2^j行对应的祖先是谁
3.将较深的点向上挪,直到两结点的深度相同
4.深度相同后,祖先可能就在上方,再走几步就到了,于是两个点同时向上移
具体的方法和代码贴在下面 ↓
具体
1.求出每个元素在树中的深度
//求每个节点在树中的深度
void dfs(int pos,int pre)//pre是pos的父节点
{
for(int i=;i<v[pos].size;i++)//枚举pos的子节点
{
register int t=v[pos][i];
if(t==pre)continue;//防止死循环
f[t][]=pos;dep[t]=dep[pos]+;
dfs(t,pos);//再从子节点向后枚举
}
}
2.用st表预处理的方法处理出f[i][j]
//求f数组(st表预处理)
for(int i=;(<<i)<=n;i++)
for(int j=;j<=n;j++)
f[j][i]=f[f[j][i-]][i-];
//f[i][j]表示元素i上方第2^j行对应的祖先是谁
3.先比较a,b两点哪个较深,将较深的点赋值给a
//把a节点变为a,b中较深的一个节点
int query(int a,int b)
{
if(dep[a]<dep[b])swap(a,b);
}
将较深的点向上挪,直到两结点的深度相同
//使a和b在同一个深度上
for(int i=;i>=;i--)
if(dep[f[a][i]]>=dep[b])
a=f[a][i];
//倒着循环是因为向上走的步数只会越来越小
4.深度相同后,祖先可能就在上方,再走几步就到了,于是两个点同时向上移
//同一深度后,再向上找公共祖先
for(int i=;i>=;i--)
if(f[a][i]!=f[b][i])
{
a=f[a][i];
b=f[b][i];
}
全部代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
vector<int> v[];
vector<int> w[];
int f[][];//f[i][j]表示i点向上2^j层的祖先
int g[][];//g[i][j]表示i点到从i向上2^j层的祖先的距离
int dep[];
int n,m;
void dfs(int pos,int pre,int depth)
{
dep[pos]=depth;
for(int i=;i<v[pos].size();i++)
{
int t=v[pos][i];
if(t==pre) continue;
f[t][]=pos;
g[t][]=w[pos][i];
dfs(t,pos,depth+);
}
}
int query(int a,int b)
{
int sum=;
if(dep[a]<dep[b]) swap(a,b);//深度较深的点
for(int i=;i>=;i--)//找到a在深度dep[b]处的祖先
{
if(dep[f[a][i]]>=dep[b])
{
sum+=g[a][i];//a到该祖先的距离
a=f[a][i];
}
}
if(a==b) return sum;//挪到相同深度后如果在同一点直接return
int x;
for(int i=;i>=;i--)//否则a和b一起往上蹦跶
{
if(f[a][i]!=f[b][i])
{
sum+=g[a][i];
a=f[a][i];
sum+=g[b][i];
b=f[b][i];
}
}
return sum+g[a][]+g[b][];//最后蹦跶到最近公共祖先的下一层,所以要再加上上一层
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
memset(dep,-,sizeof dep);//多组数据我们初始化
memset(f,,sizeof f);
memset(g,,sizeof g);
for(int i=;i<n;i++)//md
v[i].clear(),w[i].clear();
for(int i=;i<n;i++)
{
int x,y,c;
cin>>x>>y>>c;
v[x].push_back(y);
w[x].push_back(c);
v[y].push_back(x);
w[y].push_back(c);
}
int xxx=v[].size();
dfs(,,);//dfs处理出每个点的深度,以及各种... for(int i=;<<i<=n;i++)
for(int j=;j<=n;j++)
f[j][i]=f[f[j][i-]][i-],
g[j][i]=g[f[j][i-]][i-]+g[j][i-];
for(int i=;i<=m;i++)
{
int x,y;
cin>>x>>y;
if(x==y) cout<<""<<endl;
else cout<<query(x,y)<<endl;
}
}
return ;
}
lca最近公共祖先(st表/倍增)的更多相关文章
- lca最近公共祖先与树上倍增。
https://vjudge.net/contest/295298#problem/A lca 的题目 求任意两点的距离. A题是在线算法,用st表rmq来实现. https://blog.csdn. ...
- LCA最近公共祖先 ST+RMQ在线算法
对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决. 这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...
- LCA(最近公共祖先)之倍增算法
概述 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我们先介 ...
- 求LCA最近公共祖先的在线倍增算法模板_C++
倍增求 LCA 是在线的,而且比 ST 好写多了,理解起来比 ST 和 Tarjan 都容易,于是就自行脑补吧,代码写得容易看懂 关键理解 f[i][j] 表示 i 号节点的第 2j 个父亲,也就是往 ...
- LCA(最近公共祖先)模板
Tarjan版本 /* gyt Live up to every day */ #pragma comment(linker,"/STACK:1024000000,1024000000&qu ...
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...
- LCA 近期公共祖先 小结
LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...
- lca 最近公共祖先
http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)
Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...
- LCA近期公共祖先
LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...
随机推荐
- (C)结构数组
结构数组 对于大小相同但是类型不同的数组,定义结构体数组对其很有帮组.例如: char *keyword[NKEYS]; int keycount[NKEYS]; 这两个数组大小相同,因此 可以用另一 ...
- Linux Shell Script目录
目录 Linux Shell基础 开始Shell编程 代码 示例代码查看:https://github.com/Furzoom/demo-C/tree/master/src/shell
- <JAVA8新增内容>关于匿名内部集合和lambda表达式
要想说清楚JAVA中的Lambda表达式,必须想讲一下匿名内部类来帮助理解本质. 一.匿名内部类 匿名内部类适合创建那种只需要一次使用的类,例如前面介绍命令模式时所需要的Command对象,匿名内部类 ...
- layer 插件 在子页面关闭自身的方法
先取到该子页面在父级页面中的name 值 var index= parent.layer.getFrameIndex(Window.name); 然后用该方法关闭 parent.layer.clos ...
- poj1733 Parity game[带权并查集or扩展域]
地址 连通性判定问题.(具体参考lyd并查集专题该题的转化方法,反正我菜我没想出来).转化后就是一个经典的并查集问题了. 带权:要求两点奇偶性不同,即连边权为1,否则为0,压缩路径时不断异或,可以通过 ...
- ACM学习历程—FZU 2144 Shooting Game(计算几何 && 贪心 && 排序)
Description Fat brother and Maze are playing a kind of special (hentai) game in the playground. (May ...
- bzoj 1369: Gem 树形dp
题目大意 给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数 唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小.N<=10000 题解 我们可以 ...
- mysql数据库---编码格式基本操作
1.查看数据库编码格式 mysql> show variables like 'character_set_database'; 2.查看数据表的编码格式 mysql> show crea ...
- PageMethods
主要是用到ScriptManger,老知识Mark一下,ScriptManager要EnablePageMethods="true" 后台 using System.Web.Scr ...
- jdbc代码
1.jdbcutiul的代码, package gz.itcast.util; import java.io.InputStream; import java.sql.Connection; impo ...