bzoj 1787 Meet 紧急集合

Meet 紧急集合

这个题是在脖子oj(清北某奆佬给起的名字)八中oj(大视野在线评测)上的。

给出bzoj链接

这个题还是求最近公共祖先的问题。

而该题不同于别的题,它是需要求三个点的最近公共祖先。

我们就需要求出三个点两两之间的LCA。

而这三个LCA之间,必有两个是相同的。

如果两个点相同,那另一点就是那三个点的LCA。

如果三个点都相同,那么该点就是那三个点的LCA。

最后还需要统计走过的边的长度。

三个点都相同的情况很好搞,就是计算三个点与那个LCA的深度差,加起来就是答案。

但是两个点就难一点。如果lca_a_b与lca_a_c相同,就需要求出lca_b_c到a,b,c的长度,就可以转化成b,c到它们的最近公共祖先lca_b_c的长度,和lca_b_c,a到它们的最近公共祖先lca_a_b(或lca_a_c)的长度。

那么就先求出lca_b_c与b和c的深度差,再求出lca_a_b(或lca_a_c)与lca_b_c和a的深度差,加起来就是结果。

代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define N 500010
 5 #define M 1000010
 6 using namespace std;
 7 int next[M],to[M],head[N],num,size[N],deep[N],father[N],top[N],n,m,a,b,c,c1,c2,c3,ans;
 8 void add(int false_from,int false_to){
 9     next[++num]=head[false_from];
10     to[num]=false_to;
11     head[false_from]=num;
12 }
13 void dfs1(int x){
14     size[x]=1;
15     deep[x]=deep[father[x]]+1;
16     for(int i=head[x];i;i=next[i])
17         if(father[x]!=to[i]){
18             father[to[i]]=x;
19             dfs1(to[i]);
20             size[x]+=size[to[i]];
21         }
22 }
23 void dfs2(int x){
24     int mmax=0;
25     if(!top[x])
26         top[x]=x;
27     for(int i=head[x];i;i=next[i])
28         if(father[x]!=to[i]&&size[to[i]]>size[mmax])
29             mmax=to[i];
30     if(mmax){
31         top[mmax]=top[x];
32         dfs2(mmax);
33     }
34     for(int i=head[x];i;i=next[i])
35         if(father[x]!=to[i]&&to[i]!=mmax)
36             dfs2(to[i]);
37 }
38 int lca(int x,int y){
39     while(top[x]!=top[y]){
40         if(deep[top[x]]<deep[top[y]])
41             swap(x,y);
42         x=father[top[x]];
43     }
44     if(deep[x]<deep[y])return x;
45     return y;
46 }
47 int main(){
48     scanf("%d%d",&n,&m);
49     for(int i=1;i<n;++i){
50         scanf("%d%d",&a,&b);
51         add(a,b);
52         add(b,a);
53     }
54     dfs1(1);
55     dfs2(1);
56     for(int i=1;i<=m;++i){
57         scanf("%d%d%d",&a,&b,&c);
58         ans=0;
59         c1=lca(a,b);
60         c2=lca(a,c);
61         c3=lca(b,c);
62         if(c1==c2&&c2==c3){
63             ans=abs(deep[c1]-deep[a])+abs(deep[c1]-deep[b])+abs(deep[c1]-deep[c]);
64             printf("%d %d\n",c1,ans);
65         }
66         else
67             if(c1==c2){
68                 ans+=deep[b]+deep[c]-deep[c3]*2;
69                 ans+=deep[c3]+deep[a]-deep[c1]*2;
70                 printf("%d %d\n",c3,ans);
71             }
72         else
73             if(c1==c3){
74                 ans+=deep[a]+deep[c]-deep[c2]*2;
75                 ans+=deep[c2]+deep[b]-deep[c1]*2;
76                 printf("%d %d\n",c2,ans);
77             }
78         else{
79             ans+=deep[a]+deep[b]-deep[c1]*2;
80             ans+=deep[c1]+deep[c]-deep[c2]*2;
81             printf("%d %d\n",c1,ans);
82         }
83     }
84     return 0;
85 }

时间: 2024-08-14 01:16:13

bzoj 1787 Meet 紧急集合的相关文章

BZOJ 1787 AHOI2008 紧急集合 倍增LCA

题目大意:给定一棵树,多次询问到三个点距离之和最小的点和距离 首先易知到两个点距离之和最小的点一定在两点间的路径上 于是到三个点距离之和最小的点一定在两两之间路径的交点上 然后很容易就会知道这个交点一定是其中两个点的LCA(其实是我不会证) 此外为什么不会是三个点共同的LCA呢?因为三个点共同的LCA一定是至少一对点的LCA 证明略(其实我也不会证) 然后就是枚举两两之间的LCA 求一下距离 取最小即可 然后就是倍增LCA的问题了 我的倍增LCA怎么又挂了 还能不能写对了0.0 #include

bzoj 1787: [Ahoi2008]Meet 紧急集合

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3016  Solved: 1344[Submit][Status][Discuss] 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

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

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1841  Solved: 857[Submit][Status][Discuss] 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

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

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

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 2 4 4 6 6 6 Sample Output 5 2 2 5 4 1 6 0 HINT 题解: n-1条边,很明显这是一棵树 那么题目就是求3个点的LCA 我们将3个点x,y,z分别求出x,y的LCA,设为a,x,z的为b,y,z的为c 则a,b,c 3个点中必有两个相等,答案就是另外一个(自

【BZOJ-1787】Meet紧急集合 倍增LCA

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 2259  Solved: 1023[Submit][Status][Discuss] 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

BZOJ——1787: [Ahoi2008]Meet 紧急集合

http://www.lydsy.com/JudgeOnline/problem.php?id=1787 题目描述 输入 输出 样例输入 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 样例输出 5 2 2 5 4 1 6 0 提示 易发现:三个点两两求出LCA,一定至少有两个LCA相等 若只有两个相等,那聚集点就是剩下的LCA 若三个相等,那聚集点就是LCA 1 #include <algorithm> 2 #include <cstdi

BZOJ 1787 AHOI 2008 Meet 紧急集合 倍增LCA

题目大意:给出一棵树,在上满找三个点,问那个点到这三个点的距离和最短. 思路:可以证明,这个店必然是这三个点之间两个的LCA,然后枚举就可以了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 #define INF 0x3f3f3f3f using namespace std; int points

bzoj 1787 &amp;&amp; bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南

题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通过这些道路可以走遍Y岛的所有城市. 神奇的是,乘车经过每条道路所需要的费用都是一样的. 小可可,小卡卡和小YY经常想聚会,每次聚会,他们都会选择一个城市,使得3个人到达这个城市的总费用最小. 由于他们计划中还会有很多次聚会,每次都选择一个地点是很烦人的事情,所以他们决定把这件事情交给你来完成. 他们