[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 某首都城市的商人要经常 ...
随机推荐
- cordova+vue打包ios调用相机闪退解决
cordova+vue项目打包android,打开相机正常使用,但是打包ios后,需要多几个配置,才能打开,否则当调用的时候会闪退,上配置图 需要在选中的文件里面添加 <key>NSCam ...
- Python-PhantomJS的安装和使用
PhantomJS无需浏览器的Web测试: PhantomJS官网下载地址:https://phantomjs.org/download.html 下载PhantomJS zip文件,解压放置在D:\ ...
- vmware企业虚拟化平台vSphere管理与配置
├─1-CCIE-DC课程介绍.avi ├─2-vSphere-简介.avi ├─3-vSphere-新功能介绍.avi ├─4-vSphere-授权介绍.avi ├─5-vSphere-课程拓扑介绍 ...
- java递归树形菜单显示
今天写权限整好涉及到一些菜单的显示,最先想到的是递归遍历输出,但是呢在网上找了很多有关的资料没有符合自己需求的所以就自己写了一个,如果觉得靠谱 请点点关注!!!赞一个 首先看一些设计的数据库设计 菜单 ...
- django 从零开始 6 数据库模型增删改查
这些都是凭记忆写下的,有些会漏掉,在之后的笔记中会写 和flask query不同,django是使用objects进行一个查询 查询 单条记录 django 模型.bojects.get(查询的字段 ...
- 项目团队测试改进&产品测试方法的思考和改进
七月份了,2019年已过去一半: 后半年,我们要以什么样的成果来对生命唱赞歌? 我目前负责公司一个小产品线的测试,和一个大产品线的项目测试. 产品测试,我才加入3周: 经过这段时间断断续续的磨合,我对 ...
- 基于osg的python三维程序开发(二)------向量
上一篇文章展示了如何简单创建一个osg python 程序, 本篇展示了了一些基础数据结构的使用: from pyosg import * vec = osg.Vec3Array() #push ba ...
- Python模块一
logging模块 我们来说一下这个logging模块,这个模块的功能是记录我们软件的各种状态,你们现在和我一起找到红蜘蛛的那个图标,然后右键找一找是不是有个错误日志.其实每个软件都是有错误日志的,开 ...
- 【Weiss】【第03章】队列例程
前几个例程还是相当简单的,把链表即时改了一下就是队列了. 还有想了一下,决定这种例程的代码放法是:先把测试代码默认折叠放在前面,然后把实现代码默认展开放在后面. 测试代码如下: #include &l ...
- 使用C#+EmguCV处理图像入门(一)
首先我们先了解一下该库的一些相关信息 OpenCV(Open Source Computer Vision Library)是一个(开源免费)发行的跨平台计算机视觉库,可以运行在Linux.Windo ...