[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 注意到边权为一 ...
随机推荐
- 2018软工实践—Alpha冲刺(1)
o## 队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作,对多个目标检测及文字识别模型进行评估.实验 ...
- Requests库常用方法及其详解
request库七个方法详解 1. request方法 所有方法的的基础方法,三个参数:method,url,**kwargs. 1.1 method:请求方式 method参数共有七个可选的值,分别 ...
- 软工 · 第十一次作业 - Alpha 事后诸葛亮(团队)
软工 · 第十一次作业 - Alpha 事后诸葛亮(团队) 组长本次作业链接 现代软件工程 项目Postmortem 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场 ...
- 团队项目选题报告(I know)
一.团队成员及分工 团队名称:I know 团队成员: 陈家权:选题报告word撰写 赖晓连:ppt制作,原型设计 雷晶:ppt制作,原型设计 林巧娜:原型设计,博客随笔撰写 庄加鑫:选题报告word ...
- DFS(DP)---POJ 1014(Dividing)
原题目:http://poj.org/problem?id=1014 题目大意: 有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两 ...
- mnist测试
第一步:进入caffe目录 第二步:获取mnist数据集 ./data/mnist/get_mnist.sh 第三步:创建lmdb ./examples/mnist/create_mnist.sh 第 ...
- linux 虚拟网络模型介绍
第一种隔离模型 每一个虚拟机实例的网卡都有两个接口,一端接在虚拟机内部,一端接在宿主机内部,如上图所示eth0就是接在虚拟机内部的,而vnet0就是接在宿主机内部的,只要再创建一个虚 ...
- JAVA第三次笔记
- 程序员必看电影:Java 4-ever
http://blog.csdn.net/zdwzzu2006/article/details/5863068
- 使用Kettle导出excel
1.开发背景 在web项目中,经常会需要查询数据导出excel,以前比较常见的就是用poi.使用poi的时候也有两种方式,一种就是直接将集合一次性导出为excel,还有一种是分批次追加的方式适合数据量 ...