[bzoj1787] [Ahoi2008]Meet 紧急集合
来自FallDream的博客,未经允许,请勿转载,谢谢qaq
给定一棵n个点的树,m个询问,每次给出3个点,求一个点使得这个点到三个点的距离和最小。n,m<=500000
题解:很容易想到求lca。稳健一点,就把三个点两两的lca求一下,计算答案;实际上我们发现一定有两个lca相同,我们就选另一个作为答案就行啦。
#include<iostream> #include<cstdio> #define MN 500000 #define MK 20 #define INF 2000000000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,head[MN+5],dep[MN+5],cnt=0,from; int fa[MN+5][MK+2]; struct edge{int to,next;}e[MN*2+5]; void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void dfs(int x,int f) { fa[x][0]=f; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) dep[e[i].to]=dep[x]+1,dfs(e[i].to,x); } int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int k=dep[x]-dep[y],j=0;k;j++,k>>=1) if(k&1)x=fa[x][j]; if(x==y)return x; for(int i=MK;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } inline int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];} int main() { n=read();m=read(); for(int i=1;i<n;i++) ins(read(),read()); dfs(1,0); for(int j=1;j<=MK;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; for(int i=1;i<=m;i++) { int a=read(),b=read(),c=read();from=0; int l1=lca(a,b),l2=lca(a,c),l3=lca(b,c); if(l1==l2)from=l3; else if(l1==l3)from=l2; else from=l1; printf("%d %d\n",from,dis(from,a)+dis(from,b)+dis(from,c)); } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream