版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XianHaoMing/article/details/83240162
NN country
Description
有
个城市形成一棵树的形状。
有
辆双向班车往返于两个城市(中途经过的城市都会停)。
有
个人要从城市
到城市
,问最少坐几趟班车。
如果到不了,输出
。
Data Constrints
Solution
首先从城市
到城市
的搭车方案分成两类,第一类为在
和
的
下车了,第二类是没有在
处下车。
第一类比较好处理,预处理出
表示从
向上搭
趟车最上能去到哪个点,用
数组可以很快的倍增出
和
到
至少要搭多少辆车。
第二类的话先找到 和 用 数组跳到 处的前一个点,记为 和 ,就是找是否存在一趟车的路覆盖了 和 ,如果存在,那么答案显然可以少 。
至于如何判断的话,实质就是问是否有一条路径一端在 的子树内,另一端在 的子树内,算出 序便变成了一个二维数点问题,但可以不用扫描线处理,具体做法是,考虑离线, 时每遍历到一个点时,找出所有以这个点为一端的车次,并给这些车次的另一端打上加1标记,那么对于一组询问 和 , 子树内的标记和在 的子树遍历完后发生了变化,就说明存在一条路径一端在 的子树内,另一端在 的子树内,由于子树内的 序是连续的一段,所以询问子树内的标记和用树状数组就可以解决,那这题就做完了。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=51e4,M=N<<2;
int ne[M],lb[M],la[N],dfn[N],en[N],dep[N],fa[N],ans[N];
int ax[N],ay[N];
int f[N][20],g[N][20];
int xx[N],yy[N];
int u1[N],u2[N],v1[N],v2[N],jl[N];
int n,m,x,y,k,op,fs,oo,l,q;
int tr[M];
inline void llb(int a,int b)
{ne[++oo]=la[a]; la[a]=oo; lb[oo]=b;}
inline int min(int a,int b)
{return a<b?a:b;}
inline void dg(int o)
{
for(int y=la[o];y;y=ne[y]){
f[lb[y]][0]=o; dep[lb[y]]=dep[o]+1;
for(l=0;f[f[lb[y]][l]][l];++l)
f[lb[y]][l+1]=f[f[lb[y]][l]][l];
dg(lb[y]);
}
}
inline int get(int a,int b)
{
if(dep[a]>dep[b])swap(a,b);
for(int l=19;l>=0;--l)if(dep[f[b][l]]>=dep[a])b=f[b][l];
for(int l=19;l>=0;--l)if(f[b][l]!=f[a][l])b=f[b][l],a=f[a][l];
return (a!=b)?fa[a]:a;
}
inline void dfs1(int o)
{
for(int y=la[o];y;y=ne[y]){
dfs1(lb[y]);
if(dep[g[lb[y]][0]]<dep[g[o][0]])g[o][0]=g[lb[y]][0];
if(dep[g[o][0]]>=dep[o])g[o][0]=n+1;
}
}
inline void dfs(int o)
{
dfn[o]=en[o]=++op;
for(int y=la[o];y;y=ne[y]){
k=lb[y];
if(dep[g[k][0]]<dep[k]){
for(l=0;g[g[k][l]][l]!=n+1;++l)
g[k][l+1]=g[g[k][l]][l];
}else g[k][0]=n+1;
dfs(k); en[o]=en[k];
}
}
inline int get1(int a,int b)
{
if(a==b)return 0;
int aa=0;
for(int l=19;l>=0;--l)
if(g[a][l]!=n+1&&dep[g[a][l]]>dep[b])
a=g[a][l],aa=aa+(1<<l);
if(g[a][0]!=n+1)aa=aa+1;else aa=n+1;
return aa;
}
inline int get2(int a,int b)
{
int aa=0;
for(int l=19;l>=0;--l)
if(g[a][l]!=n+1&&dep[g[a][l]]>dep[b])
a=g[a][l],aa=aa+(1<<l);
fs=aa; return a;
}
inline void modify(int o,int zl)
{for(;o<=n;o=o+(o&(-o)))tr[o]=tr[o]+zl;}
inline int ask(int o)
{
int y=0;
for(;o;o=o-(o&(-o)))y=y+tr[o];
return y;
}
inline void dfs2(int o)
{
for(int y=la[o];y;y=ne[y])
if(lb[y]>2*n){
k=lb[y]-2*n;
jl[k]=ask(en[u2[k]])-ask(dfn[u2[k]]-1);
}
for(int y=la[o];y;y=ne[y])
if(lb[y]>n&&lb[y]<=2*n){
k=lb[y]-n;
modify(dfn[k],1);
}
for(int y=la[o];y;y=ne[y])
if(lb[y]<=n)dfs2(lb[y]);
for(int y=la[o];y;y=ne[y])
if(lb[y]>2*n){
k=lb[y]-2*n;
if(ask(en[u2[k]])-ask(dfn[u2[k]]-1)!=jl[k])
ans[k]=min(ans[k],v1[k]+v2[k]+1);
}
}
int main()
{
cin>>n;
fo(i,2,n){
scanf("%d",&fa[i]);
llb(fa[i],i);
}
dep[1]=1; dg(1);
fo(i,1,n)g[i][0]=n+1;
dep[n+1]=n+1;
fo(i,1,n)fo(l,0,19)g[i][l]=n+1;
scanf("%d",&m);
fo(i,1,m){
scanf("%d%d",&x,&y);
if(x==y)continue;
int z=get(x,y);
if(dep[z]<dep[g[x][0]])g[x][0]=z;
if(dep[z]<dep[g[y][0]])g[y][0]=z;
ax[i]=x; ay[i]=y;
}
dfs1(1);
dfs(1);
fo(i,1,m)if(ax[i]!=ay[i])llb(ax[i],ay[i]+n),llb(ay[i],ax[i]+n);
scanf("%d",&q);
fo(i,1,q){
scanf("%d%d",&xx[i],&yy[i]);
int z=get(xx[i],yy[i]);
ans[i]=get1(xx[i],z)+get1(yy[i],z);
u1[i]=get2(xx[i],z); v1[i]=fs;
u2[i]=get2(yy[i],z); v2[i]=fs;
if(z!=xx[i]&&z!=yy[i])llb(u1[i],i+n+n);
}
dfs2(1);
fo(i,1,q)if(ans[i]>n)puts("-1");else printf("%d\n",ans[i]);
}