题解 [BZOJ1832][AHOI2008] 聚会

题面

解析

首先对于其中的两个点\(x,y\)最近的点显然就是他们的\(lca\)(我们把它设为\(p1\)),

然后考虑第三个点\(z\)与\(p1\)的\(lca,p2\).

有以下几种情况:

  1. \(dep[p1]>=dep[p2]\)(也就是\(p2\)在\(p1\)上面或\(p1=p2\)),这时候答案显然就是\(p1\).

  2. \(dep[p1]<dep[p2]\),这时候我们求出\(p3=lca(x,z),p4=lca(y,z)\)

    1. \(dep[p3]>dep[p4]\),这时候\(p3\)显然更优(画下图或者\(yy\)一下就能理解)
    2. \(dep[p4]>dep[p3]\),同理,就是反过来...
    3. \(p3=p4\),随便选一个...

最后用深度算距离就行啦.

code(似乎有点卡常):

#include <iostream>
#include <cstdio>
#include <cstring>
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std; inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return f*sum;
} const int N=500005;
struct edge{int to,next;}e[N<<1];
int n,m;
int head[N],cnt;
int fa[N][20],dep[N]; inline void add(int x,int y){
e[++cnt]=(edge){head[x],y};head[x]=cnt;
} inline void dfs(int x,int f){
fa[x][0]=f;dep[x]=dep[f]+1;
for(int i=1;i<20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].to){
int k=e[i].next;if(k==f) continue;
dfs(k,x);
}
} inline int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--){
if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
}
if(x==y) return x;
for(int i=19;i>=0;i--){
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
} int main(){
n=read();m=read();
for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}
dfs(1,0);
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
int p1=lca(x,y),p2=lca(p1,z);
if(dep[p2]<dep[p1]){
printf("%d %d\n",p1,dep[x]-dep[p1]+dep[y]-dep[p1]+dep[p1]-dep[p2]+dep[z]-dep[p2]);
}
else{
int p3=lca(x,z),p4=lca(y,z);
if(dep[p3]>=dep[p4])
printf("%d %d\n",p3,dep[x]-dep[p3]+dep[z]-dep[p3]+dep[y]-dep[p1]+dep[p3]-dep[p1]);
else
printf("%d %d\n",p4,dep[y]-dep[p4]+dep[z]-dep[p4]+dep[x]-dep[p1]+dep[p4]-dep[p1]);
}
}
return 0;
}
上一篇:C++注意事项


下一篇:SqlServer和Oracle中一些常用的sql语句8 触发器和事务