题意
自己看。。
题解
我们可以记录一下,每一个点通过公交线可以到的深度最小的点
然后显然地,如果一个点,他往上跳一下,还在LCA下面,那么肯定是继续跳的
这个过程可以用倍增加速
然后现在就是两个点,他们任意一个跳都会跳过LCA
那么最小就是还要两步
我们只需要考虑是否存在一条线路同时过这两个点就可以了
然后这条线路肯定是过LCA的
然后考虑怎么样的线路是合法的
肯定是LCA是这个点。然后两个点分别在两个子树里面
然后转化为dfs序就是一个在LCA里面矩阵数点的问题了
如果有点,那么就是+1,否则就是+2
CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int MAX=(1<<30);
const int N=200005;
struct qq
{
int x,y,last;
}e[N];
int num,last[N];
int n,m,q;
void init (int x,int y)
{
num++;
e[num].x=x;e[num].y=y;
e[num].last=last[x];
last[x]=num;
}
int Fa[N][21];
int dep[N];
int L[N],R[N],cnt;
void dfs (int x)
{
L[x]=++cnt;
for (int u=1;u<=20;u++) Fa[x][u]=Fa[Fa[x][u-1]][u-1];
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
Fa[y][0]=x;
dep[y]=dep[x]+1;dfs(y);
}
R[x]=cnt;
}
int get_lca (int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int u=20;u>=0;u--)
if (Fa[x][u]!=0&&dep[Fa[x][u]]>=dep[y])
x=Fa[x][u];
if (x==y) return x;
for (int u=20;u>=0;u--)
if (Fa[x][u]!=Fa[y][u])
{x=Fa[x][u];y=Fa[y][u];}
return Fa[x][0];
}
struct qt
{
int id;//这是加点还是询问
int x,y;//如果是加点那么这个就是坐标,如果这个是询问,那么就是哪两个到吗
qt () {};
qt (int _id,int _x,int _y) {id=_id;x=_x;y=_y;}
};
vector<qt> s[N];
int low[N];
int fa[N][21];
int pow[21];
void update (int x,int y)
{
//printf("%d %d %d %d\n",x,y,dep[low[x]],dep[y]);
if (dep[low[x]]>dep[y]) low[x]=y;
}
void dfs1 (int x)
{
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
dfs1(y);
update(x,low[y]);
}
}
void dfs2 (int x)
{
fa[x][0]=low[x];
for (int u=1;u<=20;u++) fa[x][u]=fa[fa[x][u-1]][u-1];
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
dfs2(y);
}
}
int ans[N];
struct qy
{
int x,y;
}t[N];
void solve (int x,int y,int id)
{
int o=get_lca(x,y);
if (x==y) return ;
for (int u=20;u>=0;u--)
{
if (u!=0&&fa[x][u]==fa[x][u-1]) continue;
int xx=fa[x][u];
if (dep[xx]>dep[o])
{
ans[id]=ans[id]+pow[u];
x=xx;
}
}
for (int u=20;u>=0;u--)
{
if (u!=0&&fa[y][u]==fa[y][u-1]) continue;
int xx=fa[y][u];
if (dep[xx]>dep[o])
{
ans[id]=ans[id]+pow[u];
y=xx;
}
}
if (dep[low[x]]>dep[o]||dep[low[y]]>dep[o])
{
ans[id]=-1;
return ;
}
if (x==o||y==o)//如果一开始有一个lca
{
ans[id]++;
return ;
}
if (L[x]>L[y]) swap(x,y);
//printf("%d %d %d\n",o,x,y);
s[o].push_back(qt(id,x,y));
}
int f[N];
int lb (int x) {return x&(-x);}
void change (int x,int y)
{
while (x<=n)
{
f[x]+=y;
x=x+lb(x);
}
}
int find (int x)
{
int lalal=0;
while (x>=1)
{
lalal=lalal+f[x];
x=x-lb(x);
}
return lalal;
}
qt o[N*4];
int h[N];
bool cmp (qt x,qt y)
{
if (x.x==y.x) return (x.id==0);
else return x.x<y.x;
}
int main()
{
pow[0]=1; for (int u=1;u<=20;u++) pow[u]=(pow[u-1]<<1);
num=0;memset(last,-1,sizeof(last));
scanf("%d",&n);
for (int u=2;u<=n;u++)
{
int x;
scanf("%d",&x);
init(x,u);
}
dep[0]=MAX;dfs(1);
scanf("%d",&m);
for (int u=1;u<=m;u++)
{
int x,y;
scanf("%d%d",&x,&y);
int xx=get_lca(x,y);
//printf("%d\n",xx);
if (L[x]>L[y]) swap(x,y);//人为地让小的作为x坐标
s[xx].push_back(qt(-1,L[x],L[y]));
update(x,xx);update(y,xx);
}
dfs1(1);dfs2(1);
/*for (int u=1;u<=n;u++) printf("%d ",low[u]);
printf("\n");*/
scanf("%d",&q);
for (int u=1;u<=q;u++)
{
int x,y;
scanf("%d%d",&x,&y);
solve(x,y,u);
}
for (int u=1;u<=n;u++)
{
int t=s[u].size();cnt=0;
for (int i=0;i<t;i++)
{
// printf("%d %d %d\n",s[u][i].x,s[u][i].y,s[u][i].id);
if (s[u][i].id==-1)
{
o[++cnt]=qt(0,s[u][i].x,s[u][i].y);
}
else
{
int x=s[u][i].x,y=s[u][i].y,id=s[u][i].id;
o[++cnt]=qt(id,R[x],R[y]);
o[++cnt]=qt(-id,L[x]-1,R[y]);
o[++cnt]=qt(-id,R[x],L[y]-1);
o[++cnt]=qt(id,L[x]-1,L[y]-1);
}
}
sort(o+1,o+1+cnt,cmp);
// for (int i=1;i<=cnt;i++) printf("YES:%d %d %d\n",o[i].id,o[i].x,o[i].y);
for (int i=1;i<=cnt;i++)
{
if (o[i].id==0) change(o[i].y,1);
else
{
if (o[i].id>0)
{
// printf("OZY:%d %d\n",find(o[i].y));
h[o[i].id]=h[o[i].id]+find(o[i].y);
}
else
{
// printf("OZY:%d %d\n",find(o[i].y));
h[-o[i].id]=h[-o[i].id]-find(o[i].y);
}
}
}
for (int i=0;i<t;i++)
{
int id=s[u][i].id;
if (id==-1) change(s[u][i].y,-1);
else
{
if (h[id]>0) ans[id]++;
else ans[id]=ans[id]+2;
}
}
}
for (int u=1;u<=q;u++)
printf("%d\n",ans[u]);
return 0;
}