标签:可以转化 ret 需要 统计 scanf top oid gif 公共祖先
这个题是在脖子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 }
标签:可以转化 ret 需要 统计 scanf top oid gif 公共祖先
原文地址:http://www.cnblogs.com/jsawz/p/6815886.html