bzoj 1787 紧急集合
题目大意:
一棵树上,两个相邻点之间距离为1,每次询问三个点,
求到这三个点距离和最小的点,以及这个距离和
思路:
几乎是lca裸题
lca:倍增即可
然后求出每两个点之间的lca
画画图可知必有两个lca相等
而此时答案即为另一个lca
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cstdlib> 7 #include<set> 8 #include<map> 9 #include<vector> 10 #include<stack> 11 #include<queue> 12 #define ll long long 13 #define inf 2147383611 14 #define MAXN 1000101 15 using namespace std; 16 inline ll read() 17 { 18 ll x=0,f=1; 19 char ch;ch=getchar(); 20 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 21 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 22 return x*f; 23 } 24 int cnt,n,T,to[MAXN],first[MAXN],next[MAXN]; 25 int depth[MAXN]; 26 int f[MAXN][28]; 27 void add(int u,int v) {next[++cnt]=first[u],first[u]=cnt,to[cnt]=v;} 28 void dfs(int x,int fa) 29 { 30 for(int i=1;i<=25;i++) 31 { 32 if((1<<i)>=depth[x]) break; 33 f[x][i]=f[f[x][i-1]][i-1]; 34 } 35 for(int i=first[x];i;i=next[i]) if(to[i]!=fa) {depth[to[i]]=depth[x]+1;f[to[i]][0]=x;dfs(to[i],x);} 36 } 37 int lca(int u,int v) 38 { 39 if(depth[u]<depth[v]) swap(u,v); 40 int d=depth[u]-depth[v]; 41 for(int i=25;i>=0;i--) 42 if(d&(1<<i)) u=f[u][i]; 43 for(int i=25;i>=0;i--) 44 { 45 if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; 46 } 47 if(u==v) return v; 48 return f[u][0]; 49 } 50 int main() 51 { 52 n=read(),T=read(); 53 int a,b,c,l1,l2,l3; 54 for(int i=1;i<n;i++) {a=read(),b=read();add(a,b);add(b,a);} 55 depth[1]=1;dfs(1,0); 56 while(T--) 57 { 58 a=read(),b=read(),c=read(); 59 l1=lca(a,b),l2=lca(a,c),l3=lca(b,c); 60 if(l1==l2) printf("%d %d\n",l3,depth[b]+depth[c]-depth[l3]*2+depth[a]-depth[l1]+depth[l3]-depth[l1]); 61 else if(l1==l3) printf("%d %d\n",l2,depth[a]+depth[c]-depth[l2]*2+depth[b]-depth[l1]+depth[l2]-depth[l1]); 62 else if(l2==l3) printf("%d %d\n",l1,depth[a]+depth[b]-depth[l1]*2+depth[c]-depth[l2]+depth[l1]-depth[l2]); 63 } 64 }