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

6 4
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6

Sample Output

5 2
2 5
4 1
6 0

HINT

Source

Day1

结论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 紧急集合的更多相关文章

  1. bzoj1787 [Ahoi2008]Meet 紧急集合

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 2272  Solved: 1029 [Submi ...

  2. bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1841  Solved: 857[Submit][ ...

  3. BZOJ 1787: [Ahoi2008]Meet 紧急集合( 树链剖分 )

    这道题用 LCA 就可以水过去 , 但是我太弱了 QAQ 倍增写LCA总是写残...于是就写了树链剖分... 其实也不难写 , 线段树也不用用到 , 自己YY一下然后搞一搞就过了...速度还挺快的好像 ...

  4. 1787: [Ahoi2008]Meet 紧急集合

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1482  Solved: 652[Submit][ ...

  5. 【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 ...

  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 ...

  7. 【bzoj1787】[Ahoi2008]Meet 紧急集合

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 2466  Solved: 1117[Submit] ...

  8. BZOJ1787 [Ahoi2008]Meet 紧急集合 【LCA】

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 3578  Solved: 1635 [Submi ...

  9. LCA 【bzoj1787】[Ahoi2008]Meet 紧急集合

    LCA [bzoj1787][Ahoi2008]Meet 紧急集合 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1787 注意到边权为一 ...

随机推荐

  1. 王者荣耀交流协会Beta发布文案美工展示博客

    logo: 我们的logo是蓝底白字,非常简洁大气的设计感,上面印有我们的软件名称,更好的直观的彰显了我们的主题.我们的软件就是要迎合使用者,给使用者更加方便快捷的工作体验,更好的衡量自己的时间分配. ...

  2. OC创建对象并访问成员变量

    1.创建一个对象 Car *car =[Car new] 只要用new操作符定义的实体,就会在堆内存中开辟一个新空间 [Car new]在内存中 干了三件事 1)在堆中开辟一段存储空间 2)初始化成员 ...

  3. 对Excle的行和列进行检查 单元格类型转换代码 ;

    对Excle的行和列进行检查  转换代码 : ** * 导入信息 */ @Override public List<Object> add(HttpServletRequest reque ...

  4. rabbitmq 配置用户信息

    本文摘自:http://my.oschina.net/hncscwc/blog/262246 1. 用户管理 用户管理包括增加用户,删除用户,查看用户列表,修改用户密码. 相应的命令 (1) 新增一个 ...

  5. c 用指针操作结构体数组

    重点:指针自加,指向下一个结构体数组单元 #include <stdio.h> #include <stdlib.h> #include <string.h> #d ...

  6. apache 部署web.py

    一.安装Mod_wsgi 1.先yum -y install httpd-devel,否则会提示没有apxs 2.如果在make时 wsgi报错apxs:Error: Command failed w ...

  7. 转载:理解OAuth 2.0

    转载地址:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 作者: 阮一峰 日期: 2014年5月12日 OAuth是一个关于授权(autho ...

  8. artdialog对话框 三种样式 网址:http://www.planeart.cn/demo/artDialog/_doc/labs.html

    摇头效果 类似与wordpress登录失败后登录框可爱的左右晃动效果 // 2011-07-17 更新 artDialog.fn.shake = function (){ var style = th ...

  9. pixi.js tools

    pixi群 881784250 Awesome pixi.js tools A list of useful libs/resources/tools for renowned html5 rende ...

  10. python脚本批量生成50000条插入数据的sql语句

    f = open("xx.txt",'w') for i in range(1,50001): str_i = str(i) realname = "lxs"+ ...