[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 注意到边权为一 ...
随机推荐
- 王者荣耀交流协会Beta发布文案美工展示博客
logo: 我们的logo是蓝底白字,非常简洁大气的设计感,上面印有我们的软件名称,更好的直观的彰显了我们的主题.我们的软件就是要迎合使用者,给使用者更加方便快捷的工作体验,更好的衡量自己的时间分配. ...
- OC创建对象并访问成员变量
1.创建一个对象 Car *car =[Car new] 只要用new操作符定义的实体,就会在堆内存中开辟一个新空间 [Car new]在内存中 干了三件事 1)在堆中开辟一段存储空间 2)初始化成员 ...
- 对Excle的行和列进行检查 单元格类型转换代码 ;
对Excle的行和列进行检查 转换代码 : ** * 导入信息 */ @Override public List<Object> add(HttpServletRequest reque ...
- rabbitmq 配置用户信息
本文摘自:http://my.oschina.net/hncscwc/blog/262246 1. 用户管理 用户管理包括增加用户,删除用户,查看用户列表,修改用户密码. 相应的命令 (1) 新增一个 ...
- c 用指针操作结构体数组
重点:指针自加,指向下一个结构体数组单元 #include <stdio.h> #include <stdlib.h> #include <string.h> #d ...
- apache 部署web.py
一.安装Mod_wsgi 1.先yum -y install httpd-devel,否则会提示没有apxs 2.如果在make时 wsgi报错apxs:Error: Command failed w ...
- 转载:理解OAuth 2.0
转载地址:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 作者: 阮一峰 日期: 2014年5月12日 OAuth是一个关于授权(autho ...
- artdialog对话框 三种样式 网址:http://www.planeart.cn/demo/artDialog/_doc/labs.html
摇头效果 类似与wordpress登录失败后登录框可爱的左右晃动效果 // 2011-07-17 更新 artDialog.fn.shake = function (){ var style = th ...
- pixi.js tools
pixi群 881784250 Awesome pixi.js tools A list of useful libs/resources/tools for renowned html5 rende ...
- python脚本批量生成50000条插入数据的sql语句
f = open("xx.txt",'w') for i in range(1,50001): str_i = str(i) realname = "lxs"+ ...