bozj1787 [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之间的距离,取最小值。
这样的话核心代码如下:
代码后面的千万要看
int dist(int x,int y)
{
return dep[x]+dep[y]-2*dep[LCA(x,y)];
}//求两点距离
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
ins(x,y),ins(y,x);
}//子父链
prep(1,0);//深度与预处理
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
lca1=LCA(a,b),lca2=LCA(b,c),lca3=LCA(a,c);
ans1=dist(a,lca1)+dist(b,lca1)+dist(c,lca1);
ans2=dist(a,lca2)+dist(b,lca2)+dist(c,lca2);
ans3=dist(a,lca3)+dist(b,lca3)+dist(c,lca3);
if(ans1<=ans2&&ans1<=ans3)
{
printf("%d %d\n",lca1,ans1);
continue;
}
if(ans2<=ans1&&ans2<=ans3)
{
printf("%d %d\n",lca2,ans2);
continue;
}
if(ans3<=ans2&&ans3<=ans1)
{
printf("%d %d\n",lca3,ans3);
continue;
}
}
return 0;
}
注意了!!!
这里有一个定理:任意三个点间两两的LCA中必有2个LCA是相同的,而三个点到另一个LCA的距离则是最短的。(不要问我为什么,本人太蒟蒻没搞懂。)
这样就可以节省一些时间。
这样的代码实现如下:
#include<bits/stdc++.h>
using namespace std;
int x,y,a,b,c,ans1,ans2,ans3,n,m,pre[1000010],ch[1000010],now[500010],tot,d[500010],f[500010][20],tt;
bool flag[500010];
inline void sb(int x,int y){pre[++tot]=now[x],now[x]=tot,ch[tot]=y;}
void find(int num,int dep)
{
d[num]=dep,flag[num]=1;
for(int i=now[num];i;i=pre[i])
if(!flag[ch[i]])
f[ch[i]][0]=num,find(ch[i],dep+1);
}
int lca(int x,int y)
{
if(d[x]<d[y])
swap(x,y);
for(int i=19;i>=0;i--)
if(d[f[x][i]]>=d[y])
x=f[x][i];
//cout<<x<<" "<<y<<endl;
if(x==y)
return x;
for(int i=19;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
sb(x,y);
sb(y,x);
}
find(1,1);
for(int j=1;j<20;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
ans1=lca(a,b);
ans2=lca(b,c);
ans3=lca(a,c);
if(ans1==ans2)
{
printf("%d %d\n",ans3,d[a]+d[c]-d[ans3]+d[b]-2*d[lca(ans3,b)]);
continue;
}
if(ans1==ans3)
{
printf("%d %d\n",ans2,d[b]+d[c]-d[ans2]+d[a]-2*d[lca(ans2,a)]);
continue;
}
if(ans2==ans3)
{
printf("%d %d\n",ans1,d[a]+d[b]-d[ans1]+d[c]-2*d[lca(ans1,c)]);
continue;
}
}
}
请各位大神请教,如果入得了眼,请关注。