[codevs1036]商务旅行<LCA:tarjan&倍增>
题目链接: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&倍增>的更多相关文章
- codevs1036商务旅行(LCA)
1036 商务旅行 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 某首都城市的商人要经常到各城镇去做 ...
- [codevs1036] 商务旅行
题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任 ...
- 【codevs1036】商务旅行 LCA 倍增
1036 商务旅行 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的 ...
- C++之路进阶——codevs1036(商务旅行)
1036 商务旅行 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇 ...
- 倍增法-lca codevs 1036 商务旅行
codevs 1036 商务旅行 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某首都城市的商人要经常到各城镇去做生意 ...
- 2953: [Poi2002]商务旅行
2953: [Poi2002]商务旅行 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 8 Solved: 8[Submit][Status] Desc ...
- poj3728 商务旅行
[Description]小 T 要经常进行商务旅行,他所在的国家有 N 个城镇,标号为 1,2,3,...,N,这 N 个城镇构成一棵树.每个城镇可以买入和卖出货物,同一城镇买入和卖出的价格一样,小 ...
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...
- codevs——1036 商务旅行
1036 商务旅行 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 某首都城市的商人要经常 ...
随机推荐
- python大佬养成计划----HTML网页设计(序列)
序列化标签 1.有序标签--ol和li 有序列表标签是<ol>,是一个双标签.在每一个列表项目前要使用<li>标签.<ol>标签的形式是带有前后顺序之分的编号.如果 ...
- 【新功能】MaxCompoute禁止Full Scan功能开放
摘要: 2018年1月10日,MaxCompute禁止Full Scan功能开放.对于新创建的project默认情况下执行sql时,针对该project里的分区表不允许全表扫描,必须有分区条件指定需要 ...
- npm注册源的配置
npm注册源的更换 在墙内久了,难免会碰到撞墙的时候,所幸国内也有众多 NPM 镜像可供选择,在大多数情况下我们可以使用国内的源(比如 淘宝 NPM 镜像)去替换官方的源以加快下载包的速度.不过呢,我 ...
- 学h5前端开发前必知的三大流行趋势
学h5前端开发前必知的三大流行趋势 随着互联网时代的飞速发展,各种互联网的Web应用程序层出不穷,很多人对于HTML5前端开发的过程充满了好奇,但是却没有了解到前端开发的未来发展趋势.下面,云慧学院专 ...
- 小白的springboot之路(十六)、mybatis-plus 的使用
0-前言 mybatis plus是对mybatis的增强,集成mybatis plus后,简单的CRUD和分页就不用写了,非常方便,五星推荐: 1-集成 1-1.添加依赖 <!-- .集成my ...
- seo搜索优化技巧02-seo问答推广怎么做?
问答推广就是以用户的角度去提问,这些问题内容就是用户搜索想要知道的.简单来说通过第三方平台站在用户的角度去帮助客户解答问题,同时附带自身的品牌和产品信息就是问答推广. 常见的问答平台有百度知道. ...
- 【tomcat系列】配置tomcat远程访问
当程序部署在tomcat上后,需要监测tomcat的性能和监测tomcat的各项指标,如内存使用情况,cpu使用情况,jvm实际情况等,对于这些指标的监控,tomcat提供了访问入口,然而tomcat ...
- Flutter json 2 model with Built Value
Flutter json 2 model with Built Value Flutter中json转换model, 除了手动转之外, 就是利用第三方库做一些代码生成. 流行的库有: json_ser ...
- web自动化的三大等待
由于web网页打开后需要时间进行数据的传送,页面的渲染,所以我们在写web自动化脚本的时候,需要等待它加载完所有的页面元素,我们才进行操作或点击.同时这种等待也是为了提高脚本的稳定性. seleniu ...
- vue基础----key的作用
1.key 在虚拟dom中 标记不同的结构,for循环中需要添加上 <body> <div id="app"> <div v-if="fla ...