bzoj1787[Ahoi2008]Meet 紧急集合&bzoj1832[AHOI2008]聚会
题意:
给个树,每次给三个点,求与这三个点距离最小的点。
题解:
倍增求出两两之间的LCA后,比较容易理解的做法是挑出两个LCA再做一次LCA,比较所有挑法。但画kan出ti图jie可知其中有两个LCA是相等的,而所求就是那个与它们不等的LCA(我也不知为什么)。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 500500 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 using namespace std; 7 8 inline int read(){ 9 char ch=getchar(); int f=1,x=0; 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 11 return x*f; 12 } 13 int fa[maxn][20],dep[maxn]; 14 struct e{int t,n;}; e es[maxn*2]; int g[maxn],ess; 15 void pe(int f,int t){ 16 es[++ess]=(e){t,g[f]}; g[f]=ess; es[++ess]=(e){f,g[t]}; g[t]=ess; 17 } 18 void init(){ess=0; memset(g,0,sizeof(g));} 19 void dfs(int x,int f){ 20 for(int i=g[x];i;i=es[i].n)if(es[i].t!=f){ 21 dep[es[i].t]=dep[x]+1; fa[es[i].t][0]=x; dfs(es[i].t,x); 22 } 23 } 24 int n,m; 25 void build(){ 26 for(int j=1;(1<<j)<=n;j++)inc(i,1,n)fa[i][j]=fa[fa[i][j-1]][j-1]; 27 } 28 int lca(int x,int y){ 29 if(dep[x]<dep[y])swap(x,y); int t=dep[x]-dep[y]; 30 for(int i=0;(1<<i)<=n;i++)if(t&(1<<i))x=fa[x][i]; 31 for(int i=18;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; 32 if(x==y)return x;else return fa[x][0]; 33 } 34 int dis(int x,int y){ 35 int z=lca(x,y); return dep[x]-dep[z]+dep[y]-dep[z]; 36 } 37 int main(){ 38 n=read(); m=read(); init(); inc(i,1,n-1){int a=read(),b=read(); pe(a,b);} 39 dep[1]=0; fa[1][0]=0; dfs(1,0); build(); 40 inc(i,1,m){ 41 int a=read(),b=read(),c=read(); int x=lca(a,b),y=lca(a,c),z=lca(b,c); 42 if(x==y)printf("%d %d\n",z,dis(a,z)+dis(b,z)+dis(c,z)); 43 else if(x==z)printf("%d %d\n",y,dis(a,y)+dis(b,y)+dis(c,y)); 44 else if(y==z)printf("%d %d\n",x,dis(a,x)+dis(b,x)+dis(c,x)); 45 } 46 return 0; 47 }
20160603