大视野 1787: [Ahoi2008]Meet 紧急集合
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3067 Solved: 1365
[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
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
思路:
看到这个题我们可以很快的分析出这道题是求三点的每两点的最小公共祖先,然后再求这三个点的最小公共祖先。然而,这样显然是很麻烦的,所以我们来看看有什么简便的方法。通过观察我们可以发现这样一个问题:这三个点两两间的lca至少有两个是相同的。
如果有两个相同的lca,那集合地点就是在lca与另一点的lca处,若三个lca均相同,那集合地点一定是该点的lca了!
是不是感觉很简单,来上代码!
代码:
#include<vector> #include<stdio.h> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 500001 using namespace std; vector<int>vec[N]; int fa[N],top[N],size[N],n,m,x,y,z,ans,t,deep[N]; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch<='9'&&ch>='0') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } int lca(int x,int y) { while(top[x]!=top[y]) { if(deep[x]<deep[y]) swap(x,y); x=fa[top[x]]; } if(deep[x]>deep[y]) swap(x,y); return x; } int dfs(int x) { size[x]=1; deep[x]=deep[fa[x]]+1; for(int i=0;i<vec[x].size();i++) if(vec[x][i]!=fa[x]) { fa[vec[x][i]]=x; dfs(vec[x][i]); size[x]+=size[vec[x][i]]; } } int dfs1(int x) { int t=0; if(!top[x]) top[x]=x; for(int i=0;i<vec[x].size();i++) if(fa[x]!=vec[x][i]&&size[vec[x][i]]>size[x]) t=vec[x][i]; if(t) top[t]=top[x],dfs1(t); for(int i=0;i<vec[x].size();i++) if(fa[x]!=vec[x][i]&&vec[x][i]!=t) dfs1(vec[x][i]); } int main() { n=read(),m=read(); for(int i=1;i<n;i++) { x=read(); y=read(); vec[x].push_back(y); vec[y].push_back(x); } dfs(1); dfs1(1); for(int i=1;i<=m;i++) { x=read();y=read();z=read(); t=lca(x,y)^lca(x,z)^lca(y,z); ans=deep[x]+deep[t]-2*deep[lca(x,t)]; ans+=deep[y]+deep[t]-2*deep[lca(y,t)]; ans+=deep[z]+deep[t]-2*deep[lca(z,t)]; printf("%d %d\n",t,ans); } return 0; }