bzoj1787[Ahoi2008]Meet 紧急集合&bzoj1832[AHOI2008]聚会

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

posted @ 2016-07-20 19:45  YuanZiming  阅读(69)  评论(0编辑  收藏