挺好的一道题,本身不难,就把求两个点的LCA变为求三个点两两求LCA,不重合的点才是最优解。值得一提的是,最后对答案的处理运用差分的思想:假设两点 一点深度为d1,另一点
深度为d2,它们LCA深度为d3,这二者之间的距离即为d1+d1-2*d3,只要将这两点推广成三点即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 500000 6 using namespace std; 7 inline int read() 8 { 9 int x=0; 10 bool f=1; 11 char c=getchar(); 12 for(; !isdigit(c); c=getchar()) if(c=='-') f=0; 13 for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0'; 14 if(f) return x; 15 return 0-x; 16 } 17 int n,m; 18 long long ans; 19 int f[maxn+10][25],dep[maxn+10],t; 20 struct node 21 { 22 int from,to,nex; 23 }edge[2*maxn+10]; 24 int head[2*maxn+10],tot=0; 25 inline void add(int x,int y) 26 { 27 edge[++tot].from=x; 28 edge[tot].to=y; 29 edge[tot].nex=head[x]; 30 head[x]=tot; 31 } 32 inline void Deal_first(int u,int father) 33 { 34 dep[u]=dep[father]+1; 35 for(int i=0;i<=19;i++) 36 { 37 f[u][i+1]=f[f[u][i]][i]; 38 } 39 for(int e=head[u];e;e=edge[e].nex) 40 { 41 int v=edge[e].to; 42 if(v==father)continue; 43 f[v][0]=u; 44 Deal_first(v,u); 45 } 46 } 47 inline int LCA(int x,int y) 48 { 49 if(dep[x]<dep[y])swap(x,y); 50 for(int i=20;i>=0;i--) 51 { 52 if(dep[f[x][i]]>=dep[y])x=f[x][i]; 53 if(x==y)return x; 54 } 55 for(int i=20;i>=0;i--) 56 { 57 if(f[x][i]!=f[y][i]) 58 { 59 x=f[x][i]; 60 y=f[y][i]; 61 } 62 } 63 return f[x][0]; 64 } 65 int main() 66 { 67 n=read();m=read(); 68 for(int i=1;i<=n-1;i++) 69 { 70 int a,b; 71 a=read();b=read(); 72 add(a,b);add(b,a); 73 } 74 Deal_first(1,0); 75 for(int i=1;i<=m;i++) 76 { 77 ans=0; 78 int a,b,c; 79 a=read();b=read();c=read(); 80 int t1=LCA(a,b); 81 int t2=LCA(a,c); 82 int t3=LCA(b,c); 83 if(t1==t2)t=t3; 84 else if(t1==t3)t=t2; 85 else if(t2==t3)t=t1; 86 ans=dep[a]+dep[b]+dep[c]-dep[t1]-dep[t2]-dep[t3]; 87 printf("%d %lld ",t,ans); 88 } 89 return 0; 90 }
请各位大佬斧正(反正我不认识斧正是什么意思)