转载请注明出处,谢谢http://blog.youkuaiyun.com/bigtiao097?viewmode=contents
题意:
给一棵有n个节点的树,然后给q个询问,每次给3个点,可以任选一点为w,使得u,v到w两条路径所重合的顶点数最多;
(2≤n≤1e5,1≤q≤1e5)
思路:
假设节点1为树的根
对于每个询问给定的三个点u、v、w,先两两求出LCA(最近公共祖先),记为a、b、c,再求出三个点的LCA,记为x
- a=b=c=x,这时求x到u,v,w的最大值即可
- a、b、c中有一个不等于x,不妨设是a,a = lca(u,v)
此时求 (a到x与x到w之和)、(a到u)、(a到v )这三者的最大值
只可能有上述两种情况,自己画下图理解一下就好
求路径长度时直接利用求lca时计算出来的depth数组就行
具体代码如下:
Result:Accepted Memory:19276 KB Time : 358ms
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxv = 1e5+5;
const int maxl = 20;//log(maxv)
vector<int> G[maxv];
int root,n,q,x;
int s,f,t;
int a,b,c;
int ans;
int parent[maxv][maxl];
int depth[maxv];
void dfs(int v,int p,int d)
{
parent[v][0] = p;
depth[v] = d;
for(int i=0;i<G[v].size();i++)
if(G[v][i]!=p)
dfs(G[v][i],v,d+1);
}
void init()
{
memset(parent,-1,sizeof parent);
dfs(root,-1,0);
for(int k=1;(1<<k)<=n;k++)
for(int v=1;v<=n;v++)
{
if(parent[v][k-1]<0) parent[v][k]=-1;
else parent[v][k]=parent[parent[v][k-1]][k-1];
}
}
int lca(int u,int v)
{
if(depth[u]>depth[v]) swap(u,v);
for(int k=0;k<maxl;k++)
if(((depth[v]-depth[u])>>k)&1)
v=parent[v][k];
if(u==v) return u;
for(int k=maxl-1;k>=0;k--)
if(parent[u][k]!=parent[v][k])
{
u = parent[u][k];
v = parent[v][k];
}
return parent[u][0];
}
int main()
{
cin>>n>>q;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
G[i].push_back(x);
G[x].push_back(i);
}
root = 1;
init();
while(q--)
{
ans = 0;
scanf("%d%d%d",&s,&f,&t);
a = lca(s,f);
b = lca(s,t);
c = lca(t,f);
x = lca(c,s);
if(a==x&&b==x&&c==x)
{
ans = max(ans,abs(depth[x]-depth[s])+1);
ans = max(ans,abs(depth[x]-depth[t])+1);
ans = max(ans,abs(depth[x]-depth[f])+1);
}
else if(a!=x)
{
ans = max(ans,abs(depth[x]-depth[a])+abs(depth[x]-depth[t])+1);
ans = max(ans,abs(depth[a]-depth[s])+1);
ans = max(ans,abs(depth[a]-depth[f])+1);
}
else if(b!=x)
{
ans = max(ans,abs(depth[x]-depth[b])+abs(depth[x]-depth[f])+1);
ans = max(ans,abs(depth[b]-depth[s])+1);
ans = max(ans,abs(depth[b]-depth[t])+1);
}
else if(c!=x)
{
ans = max(ans,abs(depth[x]-depth[c])+abs(depth[x]-depth[s])+1);
ans = max(ans,abs(depth[c]-depth[t])+1);
ans = max(ans,abs(depth[c]-depth[f])+1);
}
printf("%d\n",ans);
}
}