模板

吸取洛谷P3379的教训,我决定换板子(其实本质都是倍增是一样的),把vector换成了边表

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入输出样例

输入样例#:

输出样例#:

洛谷P3379 题目要求

/*这个题,顺手就超时
抵抗超时的办法,就是读入优化,printf
真是苦了我这种常年用cin cout的孩子*/
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 500010
int n,m,s,f[maxn][],deep[maxn],head[maxn],num;
struct node{
int to,pre;
}e[maxn<<];
int qread(){
int x=,j=;
char ch=getchar();
while(ch<''||ch>''){if(ch=='-')j=-;ch=getchar();}
while(ch<=''&&ch>=''){x=x*+ch-'';ch=getchar();}
return x*j;
}
void Insert(int from,int to){
e[++num].to=to;
e[num].pre=head[from];
head[from]=num;
}
void find_deep(int from,int now,int dep){
f[now][]=from;deep[now]=dep;
for(int i=head[now];i;i=e[i].pre){
int v=e[i].to;
if(v!=from){
find_deep(now,v,dep+);
}
}
}
void find_father(){
for(int j=;j<=;j++)
for(int i=;i<=n;i++)
f[i][j]=f[f[i][j-]][j-];
}
int get(int a,int delta){
for(int i=;i<=;i++){
if(delta&(<<i))a=f[a][i];
}return a;
}
int lca(int a,int b){
if(deep[a]<deep[b])swap(a,b);
a=get(a,deep[a]-deep[b]);
if(a==b) return a;
for(int i=;i>=;i--){
if(f[a][i]!=f[b][i]){
a=f[a][i],b=f[b][i];
}
}
return f[a][];
}
int main(){
n=qread(),m=qread(),s=qread();
int x,y;
for(int i=;i<=n-;i++){
x=qread();y=qread();
Insert(x,y);
Insert(y,x);
}
find_deep(s,s,);
find_father();
for(int i=;i<=m;i++){
x=qread();y=qread();
int ans=lca(x,y);
printf("%d\n",ans);
}
return ;
}

例题

codevs1036 商务旅行

注意:

将两点处理到深度相同的过程中,走过的路径就是两点深度差

在处理两个点一起向上追溯的时候,记录的路径应该是深度差的两倍

 商务旅行
题目描述 Description
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。 你的任务是帮助该商人计算一下他的最短旅行时间。 输入描述 Input Description
输入文件中的第一行有一个整数N,<=n<= ,为城镇的数目。下面N-1行,每行由两个整数a 和b (<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。 输出描述 Output Description
在输出文件中输出该商人旅行的最短时间。 样例输入 Sample Input 样例输出 Sample Output

题目描述

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 60010
int n,m,num,head[maxn],deep[maxn],f[maxn][];
struct node{
int to,pre;
}e[maxn];
void Insert(int from,int to){
e[++num].pre=head[from];
e[num].to=to;
head[from]=num;
}
void find_deep(int from,int now,int dep){
deep[now]=dep;f[now][]=from;
for(int i=head[now];i;i=e[i].pre){
int v=e[i].to;
if(v!=from)find_deep(now,v,dep+);
}
}
void find_father(){
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
f[j][i]=f[f[j][i-]][i-];
}
int get(int now,int delta){
for(int i=;i<=;i++){
if(delta&(<<i))now=f[now][i];
}
return now;
}
int lca(int a,int b){
if(deep[a]<deep[b])swap(a,b);
if(a==b)return ;
int result=;
result+=deep[a]-deep[b];
a=get(a,deep[a]-deep[b]);
for(int i=;i>=;i--){
if(f[a][i]!=f[b][i]){
result+=*(deep[a]-deep[f[a][i]]);
a=f[a][i];b=f[b][i];
}
}
if(a!=b)result+=;
return result;
}
int main(){
scanf("%d",&n);int x,y;
for(int i=;i<n;i++){
scanf("%d%d",&x,&y);
Insert(x,y);
Insert(y,x);
}
find_deep(,,);
find_father();
scanf("%d",&m);
int ans=;
x=;
for(int i=;i<=m;i++){
scanf("%d",&y);
ans+=lca(x,y);
x=y;
}
printf("%d",ans);
}

AC

2370 小机房的树

这道题相对于上一题无非就是加了个sum数组

sum数组的处理用的倍增,和f数组相似,sum[i][j]记录的是从i向上走(1<<j)条路的总路程

注意:

在累计答案的时候,要在改变点的位置之前使用该点

ans+=sum[a][i]+sum[b][i];
a=f[a][i];b=f[b][i];

而不要

a=f[a][i];b=f[b][i];

ans+=sum[a][i]+sum[b][i];

 小机房的树
题目描述 Description
小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力 输入描述 Input Description
第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。
第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点
输出描述 Output Description
一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。 样例输入 Sample Input 样例输出 Sample Output 数据范围及提示 Data Size & Hint
<=n<=, <=m<=, <=c<=

题目描述

/*
作者:thmyl
题目:p2370 小机房的树
*/
#include<iostream>
#include<cstdio>
#define maxn 110000
using namespace std;
int head[maxn],deep[maxn],sum[maxn][],f[maxn][];
int n,m,num,ans;
struct node{
int to,v,pre;
}e[maxn];
void Insert(int from,int to,int v){
e[++num].to=to;
e[num].v=v;
e[num].pre=head[from];
head[from]=num;
}
void find_deep(int from,int now,int dep,int val){
deep[now]=dep;f[now][]=from;sum[now][]=val;
for(int i=head[now];i;i=e[i].pre){
int v=e[i].to;
if(v!=from)find_deep(now,v,dep+,e[i].v);
}
}
void find_father(){
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
f[j][i]=f[f[j][i-]][i-];
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
sum[j][i]=sum[f[j][i-]][i-]+sum[j][i-];
}
int get(int a,int delta){
for(int i=;i<=;i++){
if(delta&(<<i))ans+=sum[a][i],a=f[a][i];
}
return a;
}
int lca(int a,int b){
if(deep[a]<deep[b])swap(a,b);
if(a==b)return ;
a=get(a,deep[a]-deep[b]);
for(int i=;i>=;i--){
if(f[a][i]!=f[b][i]){
ans+=sum[a][i]+sum[b][i];
a=f[a][i];b=f[b][i];
}
}
if(a!=b)ans+=sum[a][]+sum[b][];
}
int main(){
scanf("%d",&n);
int x,y,z;
for(int i=;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
Insert(x+,y+,z);
Insert(y+,x+,z);
}
find_deep(,,,);
find_father();
scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%d%d",&x,&y);
ans=;lca(x+,y+);
printf("%d\n",ans);
}
}

AC

图论2 最近公共祖先LCA的更多相关文章

  1. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  2. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  3. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

  4. [模板] 最近公共祖先/lca

    简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...

  5. 【lhyaaa】最近公共祖先LCA——倍增!!!

    高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...

  6. 与图论的邂逅05:最近公共祖先LCA

    什么是LCA? 祖先链 对于一棵树T,若它的根节点是r,对于任意一个树上的节点x,从r走到x的路径是唯一的(显然),那么这条路径上的点都是并且只有这些点是x的祖先.这些点组成的链(或者说路径)就是x的 ...

  7. 最近公共祖先 lca (施工ing)

    声明 咳咳,进入重难点的图论算法之一(敲黑板): 题目: 洛谷 P3379 先放标程,施工ing,以后补坑!!!(实在太难,一个模板这么长 [ 不过好像还是没有 AC自动机 长哎 ],注释都打半天,思 ...

  8. POJ 1470 Closest Common Ancestors (最近公共祖先LCA 的离线算法Tarjan)

    Tarjan算法的详细介绍,请戳: http://www.cnblogs.com/chenxiwenruo/p/3529533.html #include <iostream> #incl ...

  9. 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)

    寻找最近公共祖先,示例如下: 1 /           \ 2           3 /    \        /    \ 4    5      6    7 /    \          ...

随机推荐

  1. Mac平台下的抓包神器 —— Charles

    在开发界,“抓包”这个词想必大家耳熟能详.通过抓包工具,能够获取设备在网络通讯过程中的交换数据包.在 Windows 平台上,笔者使用较多的是 Fiddler 工具,但是由于 Fiddle 使用 C# ...

  2. Machine Learning No.5: Neural networks

    1. advantage: when number of features is too large, so previous algorithm is not a good way to learn ...

  3. 关于NIO编程

    NIO概述 什么是NIO? Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式. Ja ...

  4. mysql too many connections 解决方法

    1.mysql -u root -p 回车输入密码进入mysql   2.show processlist; 查看连接数,可以发现有很多连接处于sleep状态,这些其实是暂时没有用的,所以可以kill ...

  5. VLAN虚拟局域网技术(二)-计算机网络

    本文主要知识来源于学校课程,部分知识来自于H3C及思科中国公司网页技术手册,未经许可,禁止转载.如需转载,请联系作者并注明出处. 本节主要是总结一些思科的VLAN组中的私有协议:DTP和VTP. 1. ...

  6. Mybatis-Generator_学习_02_使用Mapper专用的MyBatis Generator插件

    源码见:https://github.com/shirayner/tk-mybatis-generator 一.要点 二.具体实现 1.项目结构 2.配置 pm.xml <?xml versio ...

  7. codeforces 659G G. Fence Divercity(dp)

    题目链接: G. Fence Divercity time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  8. HDU5875Function(单调队列)

    The shorter, the simpler. With this problem, you should be convinced of this truth.      You are giv ...

  9. codevs 2144 砝码称重2

    传送门 2144 砝码称重 2  时间限制: 1 s  空间限制: 16000 KB  题目等级 : 钻石 Diamond 题解   题目描述 Description 有n个砝码,现在要称一个质量为m ...

  10. jdk安装图解--windows系统(第一次安装和第二次安装区别)

    第一次安装可参考 https://jingyan.baidu.com/article/22fe7cedc9b93e3003617f64.html 第二次安装,如已经配置好环境变量,cmd下执行java ...