[Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合
Time Limit: 20 Sec Memory Limit: 162 MB
http://www.lydsy.com/JudgeOnline/problem.php?id=1787
Description

Input

Output

Sample Input
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6
Sample Output
2 5
4 1
6 0
HINT

Source
结论1:集合点一定在某两个点的lca上
结论2: 3个点两两算出lca,至少有2个lca相同
结论3:不同的那个lca(或3个都相同的lca)就是集合点,3个点到这个点的总距离最小
证明1:如图所示,假设等待点是 3、5、10

3个点之间的路径用蓝色标注,其余路径用橙色标注
要证明结论1,可以证明以下几点:
① 集合点 选在蓝色路径上的点 一定比 选在橙色路径上的点 更优
证明:如果集合点选在橙色路径上,即三个点可以不经过集合点到达其他点,那么选橙色路径顶端的蓝色路径上一点会更优
例如 上图中 8号点要比13号点 更优
② 集合点若选的不是lca,那么集合点越靠近lca,越优。
我们假设选的点
证明:设点a,b,c,lca为a和b的lca,设选的点d不是lca,d往lca方向移动一点,设这一点为e
那么由d向e的过程,会使①2个点的路径长度-1,另外1个点的路径长度+1 或者② 3个点的路径长度各-1
例子:①在上图中选3、5、10,集合点由4向2转移 ②在上图中好像没有。。。画一个三叉树,集合点由上往下移即可
综上可证结论1
有了结论1,就可以做这个题了,3个lca挨着算一遍即可
结论2关键点:点向上的路径有且只有唯一的一条
结论3关键点:相同的那个lca一定在另一个lca的上面
这样就可以只算那一个lca即可
然后,剩下的难以描述(语文不好),画图意会吧...

代码一:算3个lca && 倍增求lca && 读入优化 结果:上图第3行
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 500001
using namespace std;
int n,m,id[N],cnt,fa[N][],p,deep[N],tmp;
int front[N],next[N*],to[N*],tot;
int lca1,lca2,lca3;
int read()
{
int x=; char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<='') { x=x*+c-''; c=getchar();}
return x;
}
void add(int x,int y)
{
to[++tot]=y; next[tot]=front[x]; front[x]=tot;
to[++tot]=x; next[tot]=front[y]; front[y]=tot;
}
void dfs(int x)
{
id[x]=++cnt;
for(int i=front[x];i;i=next[i])
if(to[i]!=fa[x][])
{
fa[to[i]][]=x;
deep[to[i]]=deep[x]+;
dfs(to[i]);
}
}
int lca(int x,int y)
{
if(x==y) return x;
if(id[x]<id[y]) swap(x,y);
for(int i=p;i>=;i--)
if(id[fa[x][i]]>id[y])
x=fa[x][i];
return fa[x][];
}
int dis(int x,int y)
{
int lc=lca(x,y);
return deep[x]+deep[y]-*deep[lc];
}
int main()
{
n=read(); m=read();
int x,y,z;
for(int i=;i<n;i++)
{
x=read(); y=read();
add(x,y);
}
dfs();
p=log(n)/log()+;
for(int j=;j<=p;j++)
for(int i=;i<=n;i++)
fa[i][j]=fa[fa[i][j-]][j-];
int ans1,ans2,tmp;
while(m--)
{
x=read(); y=read(); z=read();
lca1=lca(x,y); lca2=lca(x,z); lca3=lca(y,z);
ans1=lca1; ans2=dis(x,lca1)+dis(y,lca1)+dis(z,lca1);
tmp=dis(x,lca2)+dis(y,lca2)+dis(z,lca2);
if(tmp<ans2)
{
ans2=tmp;
ans1=lca2;
}
tmp=dis(x,lca3)+dis(y,lca3)+dis(z,lca3);
if(tmp<ans2)
{
ans2=tmp;
ans1=lca3;
}
printf("%d %d\n",ans1,ans2);
}
}
代码二:算1个lca && 倍增求lca && 读入优化 结果: 上图第2行
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 500001
using namespace std;
int n,m,id[N],cnt,fa[N][],p,deep[N],tmp,ans2;
int front[N],next[N*],to[N*],tot;
int lca1,lca2,lca3;
int read()
{
int x=; char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<='') { x=x*+c-''; c=getchar();}
return x;
}
void add(int x,int y)
{
to[++tot]=y; next[tot]=front[x]; front[x]=tot;
to[++tot]=x; next[tot]=front[y]; front[y]=tot;
}
void dfs(int x)
{
id[x]=++cnt;
for(int i=front[x];i;i=next[i])
if(to[i]!=fa[x][])
{
fa[to[i]][]=x;
deep[to[i]]=deep[x]+;
dfs(to[i]);
}
}
int lca(int x,int y)
{
if(x==y) return x;
if(id[x]<id[y]) swap(x,y);
for(int i=p;i>=;i--)
if(id[fa[x][i]]>id[y])
x=fa[x][i];
return fa[x][];
}
int dis(int x,int y)
{
int lc=lca(x,y);
return deep[x]+deep[y]-*deep[lc];
}
int main()
{
n=read(); m=read();
int x,y,z;
for(int i=;i<n;i++)
{
x=read(); y=read();
add(x,y);
}
dfs();
p=log(n)/log()+;
for(int j=;j<=p;j++)
for(int i=;i<=n;i++)
fa[i][j]=fa[fa[i][j-]][j-];
while(m--)
{
x=read(); y=read(); z=read();
lca1=lca(x,y); lca2=lca(x,z); lca3=lca(y,z);
if(lca1==lca2) tmp=lca3;
else if(lca1==lca3) tmp=lca2;
else tmp=lca1;
ans2=dis(x,tmp)+dis(y,tmp)+dis(z,tmp);
printf("%d %d\n",tmp,ans2);
}
}
代码三:算1个lca && 树链剖分求lca && 读入优化 结果:上图第1行
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 500001
using namespace std;
int n,m,tmp,ans;
int front[N],next[N*],to[N*],tot;
int lca1,lca2,lca3;
int son[N],deep[N],bl[N],fa[N];
int read()
{
int x=; char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<='') { x=x*+c-''; c=getchar();}
return x;
}
void add(int x,int y)
{
to[++tot]=y; next[tot]=front[x]; front[x]=tot;
to[++tot]=x; next[tot]=front[y]; front[y]=tot;
}
void dfs1(int x)
{
son[x]++;
for(int i=front[x];i;i=next[i])
if(to[i]!=fa[x])
{
fa[to[i]]=x;
deep[to[i]]=deep[x]+;
dfs1(to[i]);
son[x]+=son[to[i]];
}
}
void dfs2(int x,int top)
{
bl[x]=top;
int y=;
for(int i=front[x];i;i=next[i])
if(to[i]!=fa[x]&&son[to[i]]>son[y]) y=to[i];
if(!y) return;
dfs2(y,top);
for(int i=front[x];i;i=next[i])
if(to[i]!=fa[x]&&to[i]!=y) dfs2(to[i],to[i]);
}
int lca(int x,int y)
{
while(bl[x]!=bl[y])
{
if(deep[bl[x]]<deep[bl[y]]) swap(x,y);
x=fa[bl[x]];
}
return deep[x]<deep[y] ? x:y;
}
int dis(int x,int y)
{
int lc=lca(x,y);
return deep[x]+deep[y]-*deep[lc];
}
int main()
{
n=read(); m=read();
int x,y,z;
for(int i=;i<n;i++)
{
x=read(); y=read();
add(x,y);
}
dfs1();
dfs2(,);
while(m--)
{
x=read(); y=read(); z=read();
lca1=lca(x,y); lca2=lca(x,z); lca3=lca(y,z);
if(lca1==lca2) tmp=lca3;
else if(lca1==lca3) tmp=lca2;
else tmp=lca1;
ans=dis(x,tmp)+dis(y,tmp)+dis(z,tmp);
printf("%d %d\n",tmp,ans);
}
}
上图第4行为 算3个lca && 倍增求lca
[Ahoi2008]Meet 紧急集合的更多相关文章
- bzoj1787 [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 2272 Solved: 1029 [Submi ...
- bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1841 Solved: 857[Submit][ ...
- BZOJ 1787: [Ahoi2008]Meet 紧急集合( 树链剖分 )
这道题用 LCA 就可以水过去 , 但是我太弱了 QAQ 倍增写LCA总是写残...于是就写了树链剖分... 其实也不难写 , 线段树也不用用到 , 自己YY一下然后搞一搞就过了...速度还挺快的好像 ...
- 1787: [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1482 Solved: 652[Submit][ ...
- 【BZOJ1787】[Ahoi2008]Meet 紧急集合 LCA
[BZOJ1787][Ahoi2008]Meet 紧急集合 Description Input Output Sample Input 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 ...
- bzoj 1787: [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合 Description Input Output Sample Input 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 ...
- 【bzoj1787】[Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 2466 Solved: 1117[Submit] ...
- BZOJ1787 [Ahoi2008]Meet 紧急集合 【LCA】
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 3578 Solved: 1635 [Submi ...
- LCA 【bzoj1787】[Ahoi2008]Meet 紧急集合
LCA [bzoj1787][Ahoi2008]Meet 紧急集合 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1787 注意到边权为一 ...
随机推荐
- VS2015做单元测试
1.安装测试插件 2.新建测试用例 这里就用课堂练习找水王 作例子 写一个类waterKing.h和waterKing.cpp //idList.h #pragma once #include< ...
- 浅谈 Sql Server 触发器
一.触发器概念 1.1.触发器特征 1.1.1.触发器是在对表进行增.删.改时,自动执行的存储过程.触发器常用于强制业务规则,它是一种高级约束,通过事件进行触发而被执行. ...
- Spring学习 6- Spring MVC (Spring MVC原理及配置详解)
百度的面试官问:Web容器,Servlet容器,SpringMVC容器的区别: 我还写了个文章,说明web容器与servlet容器的联系,参考:servlet单实例多线程模式 这个文章有web容器与s ...
- asp.net mvc4+EF 下使用UEditor
一.从官方网站下载UEditor,http://ueditor.baidu.com/website/download.html, 我下载的是1.53.net版本
- 【EF】Entity Framework Core 软删除与查询过滤器
本文翻译自<Entity Framework Core: Soft Delete using Query Filters>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 注意 ...
- 【Quartz.Net】.net 下使用Quartz.Net
Quartz.net是作业调度框架 1. 项目中添加quartz.net的引用(这里使用nuget管理) 新建一个类TimingJob,该类主要用于实现任务逻辑 using Quartz; usi ...
- http2.0可行性研究
一.http2比http1有了更多新特性 1.使用了多路复用的技术,并发量支持比http1大几个数量级: 2.二进制分帧,改善网络延迟情况,提高传输速率: 3.支持header的数据压缩,数据体积变 ...
- window与linux查看端口被占用
本文摘写自: 百度经验 https://www.cnblogs.com/ieayoio/p/5757198.html 一.windows:开始---->运行---->cmd,或者是wind ...
- 【JavaScript】简介、<Script>标签及基本概念
一.前言 时光荏苒,岁月匆匆.今年年初进入数据平台部门转型做Web平台.要想搞好前端肯定要学好JavaScript,于是准备抓上一俩本书从基础学起. 二.内容 简介 JavaScript是 ...
- C++——内存对象 禁止产生堆对象 禁止产生栈对象
用C或C++写程序,需要更多地关注内存,这不仅仅是因为内存的分配是否合理直接影响着程序的效率和性能,更为主要的是,当我们操作内存的时候一不小心就会出现问题,而且很多时候,这些问题都是不易发觉的,比如内 ...