[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
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][21],p,deep[N],tmp; int front[N],next[N*2],to[N*2],tot; int lca1,lca2,lca3; int read() {int x=0; char c=getchar();while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') { x=x*10+c-'0'; 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][0]) {fa[to[i]][0]=x;deep[to[i]]=deep[x]+1;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>=0;i--)if(id[fa[x][i]]>id[y])x=fa[x][i];return fa[x][0]; } int dis(int x,int y) {int lc=lca(x,y);return deep[x]+deep[y]-2*deep[lc]; } int main() {n=read(); m=read();int x,y,z;for(int i=1;i<n;i++){x=read(); y=read();add(x,y);}dfs(1);p=log(n)/log(2)+1;for(int j=1;j<=p;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];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);} }
View Code
代码二:算1个lca && 倍增求lca && 读入优化 结果: 上图第2行
#include<algorithm> #include<cstdio> #include<cmath> #define N 500001 using namespace std; int n,m,id[N],cnt,fa[N][21],p,deep[N],tmp,ans2; int front[N],next[N*2],to[N*2],tot; int lca1,lca2,lca3; int read() {int x=0; char c=getchar();while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') { x=x*10+c-'0'; 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][0]) {fa[to[i]][0]=x;deep[to[i]]=deep[x]+1;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>=0;i--)if(id[fa[x][i]]>id[y])x=fa[x][i];return fa[x][0]; } int dis(int x,int y) {int lc=lca(x,y);return deep[x]+deep[y]-2*deep[lc]; } int main() {n=read(); m=read();int x,y,z;for(int i=1;i<n;i++){x=read(); y=read();add(x,y);}dfs(1);p=log(n)/log(2)+1;for(int j=1;j<=p;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];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);} }
View Code
代码三:算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*2],to[N*2],tot; int lca1,lca2,lca3; int son[N],deep[N],bl[N],fa[N]; int read() {int x=0; char c=getchar();while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') { x=x*10+c-'0'; 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]+1;dfs1(to[i]);son[x]+=son[to[i]];} } void dfs2(int x,int top) {bl[x]=top;int y=0;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]-2*deep[lc]; } int main() {n=read(); m=read();int x,y,z;for(int i=1;i<n;i++){x=read(); y=read();add(x,y);}dfs1(1);dfs2(1,1);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);} }
View Code
上图第4行为 算3个lca && 倍增求lca
转载于:https://www.cnblogs.com/TheRoadToTheGold/p/6822268.html
[Ahoi2008]Meet 紧急集合相关推荐
- 1787: [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 1482 Solved: 652 [Submit ...
- bzoj1787 [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 2272 Solved: 1029 [ Su ...
- BZOJ 1787: [Ahoi2008]Meet 紧急集合
BZOJ 1787: [Ahoi2008]Meet 紧急集合 题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都 ...
- [bzoj1787][Ahoi2008]Meet 紧急集合 倍增LCA
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 999999999 Solved: 99999999 ...
- BZOJ 1787 [Ahoi2008]Meet紧急集合 题解与分析
[Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit: 162 MB Description Input Output Sample Input ...
- BZOJ 1787 [Ahoi2008]Meet 紧急集合——LCA
1787: [Ahoi2008]Meet 紧急集合 题目传送门 解题思路 本题是裸的LCA,特殊就在是三个点的LCA,然而并没有什么关系. 三个节点两两求LCA,将会有两个一样的公共祖先,剩下的一个就 ...
- [Ahoi2008] Meet 紧急集合 (LCA+倍增+rmq-st)
1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec Memory Limit:162 MB Submit: 590 Solved: 240 [Submit][ ...
- bzoj 1787 bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)
1832: [AHOI2008]聚会 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1539 Solved: 663 [Submit][Status ...
- BZOJ1787: [Ahoi2008]Meet 紧急集合
[传送门:BZOJ1787] 简要题意: 给出有n个点的图,n-1条无向边,保证任意两点之间能互相到达,每条边的权值为1,给出m个询问,每个询问输入x,y,z,求出一个点使得三个点到这个点的距离和最短 ...
最新文章
- Nature子刊:宏基因组组装基因组实现谱系解析
- unity之定制脚本模板
- android内存优化方法,Android开发内存优化注意事项和方法
- IDEA overwrite报错、languagelevel设置不生效问题
- linux怎么用jconsole_jconsole监控linux系统的jvm使用
- 微信气泡主题设置_微信猫和老鼠主题怎么弄?猫和老鼠聊天气泡主题设置教程...
- 保护系统 用数据库加密实现数据安全
- admin.php c install,laravel-admin后台的安装
- oracle杅擂踱阀葩,Oracle常用傻瓜问题1000问
- vs2005 c++ mfc程序无法打开资源文件
- 创建与维护MySQL数据库
- 为什么用CDN给你网站加速?
- html显示网上图片不显示不出来,网页图片显示不出来,教您网页不显示图片怎么办...
- 大数据小项目之电视收视率企业项目01
- 从交互设计“流行元素”中启发
- 校园招聘之Offer、三方协议、两方协议、劳动合同都是什么?怎样避免被坑?...
- could not find included file 'pods/target support files/pods-runner/pods-runner.debug.xcconfig 什么问题
- Java字符串与数组的互相转换
- 目前流行的几种软件的压缩比较
- 音视频常见问题分析和解决:HLS切片丢帧引起的视频卡顿问题排查
热门文章
- log4j个人使用整理
- node.js(一)
- vcenter converter 转换xenserver下linux的错误
- 线性时间选择问题——分治
- 2018 react 大会_React Conf 2018的经验教训
- 播客#47:劳伦斯·布拉德福德
- yyyy-MM-dd HH:mm:ss和yyyy-MM-dd hh:mm:ss
- PostgreSQL 9.3 beta2 stream replication primary standby switchover bug?
- centos 6.4 SVN服务器多个项目的权限分组管理
- 连接不上ftp解决方案