1036 商务旅行

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
题目描述 Description

某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。

假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。

你的任务是帮助该商人计算一下他的最短旅行时间。

输入描述 Input Description

输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=ab<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。

输出描述 Output Description

在输出文件中输出该商人旅行的最短时间。

样例输入 Sample Input
5
1 2
1 5
3 5
4 5
4
1
3
2
5
样例输出 Sample Output

7


题解:
  这道题主要是用来巩固lca和倍增算法的,是一道模板题。一个简单的树上倍增,找最近公共祖先。注意局部ans的细节处理,不是对整体相乘,而是对当前步数乘以2。然后借鉴了网上的博客的另一种计算方法:用depth来计算。写第一遍时又把倍增递推写错了。。注意数组开两倍。。
我的方法:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 30005
using namespace std;
int n,m,city[maxn],ans,fist;
int tot,he[maxn],to[maxn*],ne[maxn*];
bool flag[maxn];
int f[][maxn],depth[maxn];
void add(int a,int b)
{
tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
}
void build (int x)
{
for (int i=he[x];i;i=ne[i])
if (!flag[to[i]]){
flag[to[i]]=true;
depth[to[i]]=depth[x]+;
f[][to[i]]=x;
build(to[i]);
}
}
void bz()
{
for (int i=;i<=;i++)
for (int j=;j<=n;j++)
f[i][j]=f[i-][f[i-][j]];
}
int lca(int a,int b)
{
int mi=;
if (depth[a]<depth[b]) swap(a,b);
int derta=depth[a]-depth[b];
for (int i=;i<=;i++)
{
if (<<i & derta)
{
mi+=(<<i);
a=f[i][a];
}
}
if (a==b) return mi;
for (int i=;i>=;i--)
{
if (f[i][a]!=f[i][b]) {
a=f[i][a];
b=f[i][b];
int p=(<<i);p*=;//not mi+=(1<<i);mi*=2;
mi+=p;
}
}
a=f[][a];b=f[][b];
mi+=;
return mi;
}
int main()
{
freopen("codevs1036.in","r",stdin);
cin>>n;
for (int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
flag[]=true;
depth[]=;
build();
bz();
cin>>m;cin>>fist;
for (int i=;i<m;i++)
{
int x;scanf("%d",&x);
int y=lca(fist,x);
ans+=y;
fist=x;
}
cout<<ans<<endl;
return ;
}

借鉴方法:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 30005
using namespace std;
int n,m,city[maxn],ans,fist;
int tot,he[maxn],to[maxn*],ne[maxn*];
bool flag[maxn];
int f[][maxn],depth[maxn];
void add(int a,int b)
{
tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
}
void build (int x)
{
for (int i=he[x];i;i=ne[i])
if (!flag[to[i]]){
flag[to[i]]=true;
depth[to[i]]=depth[x]+;
f[][to[i]]=x;
build(to[i]);
}
}
void bz()
{
for (int i=;i<=;i++)
for (int j=;j<=n;j++)
f[i][j]=f[i-][f[i-][j]];
}
int lca(int a,int b)
{
//int mi=0;
if (depth[a]<depth[b]) swap(a,b);
int derta=depth[a]-depth[b];
for (int i=;i<=;i++)
{
if (<<i & derta)
{
//mi+=(1<<i);
a=f[i][a];
}
}
if (a==b) return a;
for (int i=;i>=;i--)
{
if (f[i][a]==f[i][b]) continue;
else {
a=f[i][a];
b=f[i][b];
// mi+=(1<<i);mi=(mi<<1);
}
}
// a=f[0][a];b=f[0][b];
//mi+=2;
return f[][a];
}
int main()
{
freopen("codevs1036.in","r",stdin);
cin>>n;
for (int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
flag[]=true;
depth[]=;
build();
bz();
cin>>m;cin>>fist;
for (int i=;i<m;i++)
{
int x;scanf("%d",&x);
ans+=depth[fist]+depth[x]-*depth[lca(fist,x)];
fist=x;
}
cout<<ans<<endl;
return ;
}

【codevs1036】商务旅行 LCA 倍增的更多相关文章

  1. [codevs1036]商务旅行<LCA:tarjan&倍增>

    题目链接:http://codevs.cn/problem/1036/ 今天翻箱倒柜的把这题翻出来做了,以前做的时候没怎么理解,所以今天来重做一下 这题是一个LCA裸题,基本上就把另一道裸题小机房的树 ...

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

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

  3. codevs1036商务旅行(LCA)

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

  4. codevs 1036 商务旅行 (倍增LCA)

    /* 在我还不知道LCA之前 暴力跑的SPFA 70分 三个点TLE */ #include<iostream> #include<cstdio> #include<cs ...

  5. [codevs1036] 商务旅行

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

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

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

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

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

  8. 【codevs2370】小机房的树 LCA 倍增

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0 ...

  9. LCA——倍增求解

    LCA,即最近公共祖先,用于解决树上两点的最近公共祖先问题. ; lca(1,2)=3;(原谅我的绘画水平) LCA的求解有三种算法(我知道的)——tarjan,倍增,线段树(我只会两种),NOIp之 ...

随机推荐

  1. Python循环嵌套

    可以在循环体内嵌入其他的循环体,如在while循环中可以嵌入for循环, 反之,你可以在for循环中嵌入while循环. 实例: 以下实例使用了嵌套循环输出3~13之间的素数: 以上实例输出结果: F ...

  2. WebKit渲染基础(转载 学习中。。。)

    概述 WebKit是一个渲染引擎,而不是一个浏览器,它专注于网页内容展示,其中渲染是其中核心的部分之一.本章着重于对渲染部分的基础进行一定程度的了解和认识,主要理解基于DOM树来介绍Render树和R ...

  3. eclipse插件安装 (zhuan)

    https://my.oschina.net/gxs2012/blog/205875 http://blog.csdn.net/zhujiaxing666666/article/details/150 ...

  4. valueForKeyPath的妙用(转)

    可能大家对 - (id)valueForKeyPath:(NSString *)keyPath 方法不是很了解. 其实这个方法非常的强大,举个例子: NSArray *array = @[@" ...

  5. Oracle session inactive状态临时表数据未清空问题

    问题描述:Oracle数据库,java代码使用某数据库实例,获取connection并在使用结束关闭,而session未销毁,而是状态变为inactive从而导致临时表数据未清空. Oracle临时表 ...

  6. spring boot学习

    window10的环境下 使用apache-maven-3.3.9 到https://github.com/spring-projects/spring-boot 下载源码包,解压到c:\spring ...

  7. Nodejs开发框架Express3.0开发手记–从零开始

    转载请注明出处: http://blog.fens.me/nodejs-express3/ 程序代码已经上传到github有需要的同学,自行下载. https://github.com/bsspiri ...

  8. 关于iOS7 设计师需要了解的十件事

    在今年的WWDC上,苹果推出了采用全新设计语言打造的iOS7.新系统弃用了诸如皮革.木质一类的伪3D拟真效果,取而代之的是更加简洁轻量的设计路线,其中文字排版成了重头戏,另外在某些方面也受到了扁平化设 ...

  9. 经典排序算法---冒泡排序(Bubble Sort)

    原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换, 这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到倒数第二位时结束 void Bubble ...

  10. struts2在pom.xml中的配置

    <dependencies> <dependency> <groupId>org.apache.struts</groupId> <artifac ...