题目链接:http://codevs.cn/problem/1036/

今天翻箱倒柜的把这题翻出来做了,以前做的时候没怎么理解,所以今天来重做一下

这题是一个LCA裸题,基本上就把另一道裸题小机房的树拿出来改一改就行

但LCA也有两种方式,倍增和tarjan,倍增我个人觉得很好理解,tarjan就有点迷了

所以我就用了两种方式打这一道题

倍增:

倍增的做法就是数组f[i][j]表示从i点往上走2^j次方个点可以到达哪个点,

然后进行一个树上倍增,记录下一个深度dep,然后让我们求的两点到同一深度,如果是同一点就return

不是同一点就倍增,倍增这个位置的操作和rmq差不多了,就是找到可以最大跳跃的深度,然后不断找。。直到差一个深度到最近公共祖先

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdlib>
#define maxn 30005
using namespace std; struct edge{
int u,v,nxt;
}e[maxn*]; int n,m,a[maxn],now[maxn],f[maxn][];
int head[maxn],dep[maxn],vis[maxn],ans; int tot;
void adde(int u,int v){
e[tot]=(edge){u,v,head[u]};
head[u]=tot++;
} void first(){
for(int j=;j<=;j++){
for(int i=;i<=n;i++){
f[i][j]=f[f[i][j-]][j-];
}
}
} void build(int u){
for(int i=head[u];i!=-;i=e[i].nxt){
int v=e[i].v;
if(!vis[v]){
f[v][]=u;
dep[v]=dep[u]+;
vis[v]=;
build(v);
}
}
} int up(int x,int d){
for(int i=;i<=d;i++)
x=f[x][];
return x;
} int find(int x,int y){
if(dep[x]<dep[y])swap(x,y);//手动使x深度深一些
if(dep[x]!=dep[y]){
int dd=dep[x]-dep[y];
x=up(x,dd);
}
if(x==y){return x;}
for(int j=;j>=;j--){
if(f[x][j]!=f[y][j]){
x=f[x][j];y=f[y][j];
}
}
return f[x][];
} int main(){
memset(head,-,sizeof(head));
memset(dep,,sizeof(dep));
scanf("%d",&n);
for(int i=;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
adde(x,y);adde(y,x);
}vis[]=;
build();
first();
scanf("%d",&m);
now[]=;
for(int i=;i<=m;i++){
scanf("%d",&now[i]);
int lca=find(now[i-],now[i]);
ans+=dep[now[i-]]+dep[now[i]]-*dep[lca];
}
printf("%d",ans);
}

倍增

tarjan:

虽然有些大佬觉得tarjan比倍增好理解,可能是由于我太弱导致我不能理解tarjan,说实话我觉得tarjan这个算法本身就很迷

tarjan的步骤:

1.判断与u相连的点,如果没来过就继续往深搜索下去

2.用并查集维护u,v的关系,讲两个点合并,将v标记来过

3.查找与u有询问关系的点,如果那个点已经被标记来过就继续

4.这时候找到的v的所属的并查集数组fa[v]储存的就是u,v的最近公共祖先

5.这时候u,v的距离就是u的深度+v的深度-两个最近公共祖先深度

  dep[u]+dep[v]-2*dep[fa[v]];

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdlib>
#define maxn 30005
using namespace std; struct node{
int u,v,nxt,w;
}e[maxn*],q[maxn*]; int ans,n,m,head[maxn],heaq[maxn],dep[maxn];
int low[maxn],dfn[maxn],fa[maxn],num;
int now[maxn],cnt,vis[maxn],vise[maxn]; int tot;
void adde(int u,int v){
e[tot]=(node){u,v,head[u],};
head[u]=tot;tot++;
} int toq;
void addp(int u,int v,int w){
q[toq]=(node){u,v,heaq[u],w};
heaq[u]=toq;toq++;
} int find(int x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
} void tarjan(int u){
num++;fa[u]=u;
dfn[u]=low[u]=num;vis[u]=;
for(int i=head[u];i!=-;i=e[i].nxt){
int v=e[i].v;
if(!dfn[v]){
dep[v]=dep[u]+;
tarjan(v);
fa[v]=u;
}
}
for(int i=heaq[u];i!=-;i=q[i].nxt ){
int v=q[i].v;
if(vis[v]&&!vise[q[i].w]){
vise[q[i].w]=;
ans+=dep[v]+dep[u]-*dep[find(v)];
}
} } int main(){
memset(head,-,sizeof(head));
memset(heaq,-,sizeof(heaq));
scanf("%d",&n);
for(int i=;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
adde(x,y);adde(y,x);
}
scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%d",&now[i]);
if(i==&&now[i]!=)addp(,now[i],i);
else {
addp(now[i-],now[i],i);addp(now[i],now[i-],i);
}
}dep[]=;
tarjan();
printf("%d",ans);
}

我一个同学教导我,如果你tarjan不理解就画图推,还是推不出来就背就行了,反正又不难背

[codevs1036]商务旅行<LCA:tarjan&倍增>的更多相关文章

  1. codevs1036商务旅行(LCA)

    1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 某首都城市的商人要经常到各城镇去做 ...

  2. [codevs1036] 商务旅行

    题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任 ...

  3. 【codevs1036】商务旅行 LCA 倍增

    1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的 ...

  4. C++之路进阶——codevs1036(商务旅行)

    1036 商务旅行 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇 ...

  5. 倍增法-lca codevs 1036 商务旅行

    codevs 1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 某首都城市的商人要经常到各城镇去做生意 ...

  6. 2953: [Poi2002]商务旅行

    2953: [Poi2002]商务旅行 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 8  Solved: 8[Submit][Status] Desc ...

  7. poj3728 商务旅行

    [Description]小 T 要经常进行商务旅行,他所在的国家有 N 个城镇,标号为 1,2,3,...,N,这 N 个城镇构成一棵树.每个城镇可以买入和卖出货物,同一城镇买入和卖出的价格一样,小 ...

  8. CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )

    CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...

  9. codevs——1036 商务旅行

    1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 某首都城市的商人要经常 ...

随机推荐

  1. 面试题57-II.和为s的连续正数序列

    面试题57-II.和为s的连续正数序列 1.题目 LeetCode-面试题57-II.和为s的连续正数序列 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数 ...

  2. 利用GitHub制作在线炫酷简历

    首先我们先体验一下炫酷简历.然后决定我们要不要使用. https://jessezhao1990.github.... 如何使用本项目部署你自己的在线简历 1. 书写简历 在src文件夹里面有个con ...

  3. <select>标签,不要在select标签中写value属性!!!

    <select> select标签,一个选择框标签,在开发中很多时候会用到这个标签,例如选择生日19**年,或者在segmentfault中编辑文章时选择'原创','转载',还是'翻译'等 ...

  4. Python基础-两个乒乓球队进行比赛,各出三人。

    两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人.已抽签决定比赛名单.有人向队员打听比赛的名单.a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单. L1 = [ ...

  5. 在Tomcat上发布Web项目的方式

    一. Tomcat的使用: 安装:解压压缩包即可 注意:安装目录不能有中文 目录结构: ①bin:可执行文件 ②conf:可执行文件 ③lib:依赖的jar包 ④logs:日志文件 ⑤:temp:临时 ...

  6. jenkins操作

    jenkins忘记用户名以及登录密码的解决方法 1.jenkins 根目录下找到config.xml,修改配置  <useSecurity>true</useSecurity> ...

  7. 【图文+视频新手也友好】Java一维数组详细讲解(内含练习题答案+详解彩蛋喔~)

    目录 视频讲解: 一.数组的概述 二.一维数组的使用 三.Arrays工具类中的sort方法(sort方法用的多,我们具体讲一下) 四.数组中的常见异常 五.一维数组练习题 六.彩蛋(本期视频使用的P ...

  8. 【BIM】BIMFACE中创建矢量文本[下篇]

    背景 在上一篇文章中,我们通过THREEJS创建了矢量文本,并添加到了BIMFACE场景中,但是仅仅加入到场景中并不是我们的目的,我们的目的是把这种矢量文本加到指定的构件或者空间上,以此标识该构件或空 ...

  9. npm 安装包总结

    1.前端可视化json:vue-json-viewer; 2.富文本编辑: vue-quill-editor;    https://www.cnblogs.com/ZaraNet/p/1020922 ...

  10. [BUG]excel复制到input含有不可见内容(零宽字符)

    现象 excel手机号复制到input框子, length长度和可见长度不一致. "‭176xxxx1115‬" 长度是 13 而不是 11. 原因 手机号前后被 excel 插入 ...