首先思考线路只有从祖先到子孙的链的情况,对于询问的两个点 \(x\) 和 \(y\),我们肯定要先从 \(x\) 跳到它们的 LCA,再从 LCA 跳到 \(y\)。由于从 LCA 到 \(y\) 的过程和从 \(y\) 到 LCA 的过程是等价的,所以我们可以先算出每个点在经过一定数量的线路时最远能到达哪个祖先。
暴力跳肯定不行,考虑倍增,记 \(f_{x,i}\) 表示从 \(x\) 开始往上跳,经过 \(2^{i}\) 条线路时最远能跳到的点。显然在得到每条线路的两端点 \(x\) 和 \(y\) 时我们可以更新 \(f_{x,0}\) 和 \(f_{y,0}\) 为 \(x\) 和 \(y\) 的 LCA(如果 LCA 的深度更小的话)。对于链上的其它点,在输入所有线路后我们进行一次 dfs 判断每个点 \(x\) 的儿子 \(son\) 的 \(f_{son,0}\) 能否更新 \(f_{x,0}\)。最后倍增求出整个 \(f\) 数组,询问时直接按照 \(f\) 的值计算答案即可。
接下来考虑正常情况,对于不是从祖先到子孙的链的线路,我们考虑将它拆成一条从 LCA 到 \(x\) 的链和一条从 LCA 到 \(y\) 的链,统计答案时考虑是否要经过这条线路的拐弯处,如果要就将答案减 \(1\)。考虑如何判断答案是否需要减,记询问的两个点为 \(qx\) 和 \(qy\),记 \(qx\) 到 LCA 的链上 LCA 的儿子为 \(a\),\(qy\) 到 LCA 的链上 LCA 的儿子为 \(b\)。显然如果存在一条可以经过拐弯的线路(记两端点为 \(x\) 和 \(y\)),那么 \(x\) 肯定在 \(a\) 的子树中,\(y\) 肯定在 \(b\) 的子树中。转换一下也就是 \(dfn_a \le dfn_x \le dfn_a+siz_a-1\) 且 \(dfn_b \le dfn_y \le dfn_b+siz_b-1\)。这样就转化成了二维数点问题,计算答案是否大于 \(0\) 即可,如果大于那最后就要减。
#include<bits/stdc++.h>
#define MAXN 400005
#define int long long
using namespace std;
const int inf=1e18;
int id,n,m,q,head[MAXN],cnt,fa[MAXN][22],f[MAXN][22],deep[MAXN],tree[MAXN],dfn[MAXN],num,ans[MAXN],qans[MAXN],bot[MAXN];
int lb(int x){return x&(-x);
}
void add(int x,int y){for(int i=x;i<=n;i+=lb(i))tree[i]+=y;
}
int que(int x,int y){int tans=0;for(int i=y;i;i-=lb(i))tans+=tree[i];for(int i=x-1;i;i-=lb(i))tans-=tree[i];return tans;
}
struct Edge{int value,next;
}edge[MAXN];
void addedge(int u,int v){edge[++cnt].value=v;edge[cnt].next=head[u];head[u]=cnt;
}
void dfs1(int x,int father){fa[x][0]=father;deep[x]=deep[father]+1;dfn[x]=++num;;for(int i=1;i<=21;i++)fa[x][i]=fa[fa[x][i-1]][i-1];for(int i=head[x];i;i=edge[i].next){int y=edge[i].value;if(y!=father){dfs1(y,x);}}bot[x]=num;
}
int LCA(int x,int y){if(deep[x]<deep[y])swap(x,y);for(int i=21;i>=0;i--){if(deep[fa[x][i]]>=deep[y])x=fa[x][i];} if(x==y)return x;for(int i=21;i>=0;i--){if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];}return fa[x][0];
}
void dfs2(int x){for(int i=head[x];i;i=edge[i].next){int y=edge[i].value;if(y!=fa[x][0]){dfs2(y);if(!f[x][0]||(f[y][0]&&deep[f[y][0]]<deep[f[x][0]])){f[x][0]=f[y][0];}}}
}
struct Node{int x,y,k,f,id;
}p[MAXN*4];
int tcnt;
bool cmp(Node x,Node y){return x.x==y.x?x.id<y.id:x.x<y.x;
}
signed main(){
// freopen("metro.in","r",stdin);
// freopen("metro.out","w",stdout);scanf("%lld",&n);for(int i=2;i<=n;i++){int v;scanf("%lld",&v);addedge(i,v),addedge(v,i);}dfs1(1,0);scanf("%lld",&m);for(int i=1;i<=m;i++){int x,y;scanf("%lld%lld",&x,&y);if(dfn[x]>dfn[y])swap(x,y);int l=LCA(x,y);if(!f[x][0]||(deep[l]<deep[f[x][0]]))f[x][0]=l;if(!f[y][0]||(deep[l]<deep[f[y][0]]))f[y][0]=l;p[++tcnt]=(Node){dfn[x],dfn[y],0,0,0};}dfs2(1);for(int i=1;i<=n;i++)if(f[i][0]==i)f[i][0]=0;for(int i=1;i<=21;i++){for(int j=1;j<=n;j++){f[j][i]=f[f[j][i-1]][i-1];}}scanf("%lld",&q);for(int i=1;i<=q;i++){int x,y;scanf("%lld%lld",&x,&y);if(dfn[x]>dfn[y])swap(x,y);int l=LCA(x,y);if(x==y){ans[i]=0;continue;}for(int j=21;j>=0;j--)if(f[x][j]&&deep[f[x][j]]>deep[l])x=f[x][j],ans[i]+=(1<<j);for(int j=21;j>=0;j--)if(f[y][j]&&deep[f[y][j]]>deep[l])y=f[y][j],ans[i]+=(1<<j);if((!f[x][0]&&x!=l)||(!f[y][0]&&y!=l)){ans[i]=-1;continue;}if(l==x||l==y)ans[i]++;else{ans[i]+=2;p[++tcnt]=(Node){bot[x],bot[y],1,1,i};p[++tcnt]=(Node){dfn[x]-1,bot[y],-1,1,i};p[++tcnt]=(Node){bot[x],dfn[y]-1,-1,1,i};p[++tcnt]=(Node){dfn[x]-1,dfn[y]-1,1,1,i};}}sort(p+1,p+tcnt+1,cmp);for(int i=1;i<=tcnt;i++){if(p[i].f==0)add(p[i].y,1);else qans[p[i].id]+=que(1,p[i].y)*p[i].k;}for(int i=1;i<=q;i++){printf("%lld\n",ans[i]-(qans[i]>0));}return 0;
}