题目描述
传送门:http://codeforces.com/contest/983/problem/E
题解
首先有一个很显然的贪心策略,我们对于每个节点预处理出从它出发向上乘一次车最远能到哪。
对于一次询问,两个点x,y,我们先让这两个点贪心地往lca方向跑。
这样x点跑了a次到了lx点,y点跑了b次到了rx点。
如果lx到rx可以乘一次车到达,那么答案是a+b+1,否则答案就是a+b+2。
所以问题就转化成了给两个点x,y,询问它们的子树中是否存在可以直达的路径。
一种暴力办法是直接上树套树,树状数组套个set就好了,题目时限3秒,在cf上应该能过。
考虑少一个log的做法。
我们对于一组点lx,rx,它们对应的dfs序区间是 [L[lx],R[lx]] 和 [L[rx],R[rx]]。
先dfs一遍这棵树,对于每条巴士线路,当访问到它的起点的时候,将它的终点赋上权值。
如果我们将 [L[lx],R[lx]] 区间内出发的路径所对应的终点的权值扣回去之后 [L[rx],R[rx]] 的权值和扣回去之前不一样那么就存在一条可以直达的路径。
在写的时候,我们按dfs序跑一遍,一边跑一边修改。
我们在访问到L[lx]-1 和 R[lx]的时候分别求一下 [L[rx],R[rx]]的值,把它们相减判断一下就好了。
区间和拿个树状数组搞搞就好了。
代码
#include
#define N 200005
#define D 18
using namespace std;
int n,m,Q,f[N][D+1],w[N][D+1],g[N],sum[N],ans[N];
int k,la[N],ff[N*2],dep[N],L[N],R[N],cnt,c[N];
struct node{int a,b;}e[N*2];
vectorq[N];
vector<int>t[N],h[N];
void add(int a,int b)
{
e[++k]=(node){a,b};ff[k]=la[a];la[a]=k;
e[++k]=(node){b,a};ff[k]=la[b];la[b]=k;
}
class bit
{
public:
void modify(int x,int val)
{
for(;x<=n;x+=x&-x)c[x]+=val;
}
int qry(int x)
{
int res=0;
for(;x;x-=x&-x)res+=c[x];
return res;
}
}T;
void dfs1(int x)
{
L[x]=++cnt;
for(int i=1;i<=D;i++)
w[x][i]=w[w[x][i-1]][i-1];
for(int a=la[x];a;a=ff[a])
if(e[a].b!=w[x][0])
dep[e[a].b]=dep[x]+1,dfs1(e[a].b);
R[x]=cnt;
}
void dfs2(int x)
{
g[x]=x;
for(int i=0;ix].size();i++)
if(dep[h[x][i]]x]])g[x]=h[x][i];
for(int a=la[x];a;a=ff[a])
if(e[a].b!=w[x][0])
{
dfs2(e[a].b);
if(dep[g[e[a].b]]x]])g[x]=g[e[a].b];
}
f[x][0]=g[x];
}
void prepare()
{
for(int j=1;j<=D;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int x,int y)
{
if(dep[x]y])swap(x,y);
for(int i=D;i>=0;i--)
if(dep[w[x][i]]>=dep[y])x=w[x][i];
if(x==y)return x;
for(int i=D;i>=0;i--)
if(w[x][i]!=w[y][i])x=w[x][i],y=w[y][i];
return w[x][0];
}
node work(int x,int pos)
{
if(x==pos)return (node){x,0};
int res=0;
for(int i=D;i>=0;i--)
if(dep[f[x][i]]>dep[pos])x=f[x][i],res+=(1<if(f[x][0]==x)return (node){x,-1};
return (node){x,res};
}
int main()
{
int x,y,id,inv,pos;node A,B;
scanf("%d",&n);
for(int i=2;i<=n;i++)
scanf("%d",&w[i][0]),add(w[i][0],i);
dep[1]=1;dfs1(1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);pos=lca(x,y);
if(L[x]>L[y])swap(x,y);
t[L[x]].push_back(L[y]);
if(dep[pos]x])h[x].push_back(pos);
if(dep[pos]y])h[y].push_back(pos);
}
scanf("%d",&Q);dfs2(1);prepare();
for(int i=1;i<=Q;i++)
{
scanf("%d%d",&x,&y);pos=lca(x,y);
A=work(x,pos);B=work(y,pos);
if(A.b==-1||B.b==-1){ans[i]=-1;continue;}
if(x==pos||y==pos){ans[i]=A.b+B.b+1;continue;}
ans[i]=A.b+B.b+2;x=A.a;y=B.a;
if(L[x]>L[y])swap(x,y);
q[L[x]-1].push_back((node){y,-i});
q[R[x]].push_back((node){y,i});
}
for(int i=1;i<=n;i++)
{
for(int j=0;j1);
for(int j=0;j<q[i].size();j++)
{
inv=(q[i][j].b>0?1:-1);
x=q[i][j].a;id=q[i][j].b*inv;
sum[id]+=inv*(T.qry(R[x])-T.qry(L[x]-1));
}
}
for(int i=1;i<=Q;i++)
printf("%d\n",ans[i]-(sum[i]>0));
return 0;
}