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 }
View Code

 

posted @ 2017-05-06 10:15  江屿  阅读(265)  评论(0编辑  收藏  举报