CF983E

发布时间 2023-11-12 13:11:11作者: mRXxy0o0

分析

很明显,有一个贪心的性质,对于每一次选择路线,一定会选择从当前点能走得最远的一条。

这样就得到了一个暴力做法:预处理好每个点向祖先走得最远的一条路,对于每次询问,两个点暴力上跳,在最近公共祖先处特判一下是否可以一下走完即可。

考虑优化这个过程,找最近公共祖先和上跳都可以倍增处理。唯一的问题是最近公共祖先处的特判。

假设现在已经跳到了最靠上的点对 \((u,v)\),考虑是否有一条直通的线路连接它们。这是一个 DFS 序上的二维数点问题。

具体地,我们需要寻找一条线路满足起点在 \(u\) 的子树中,终点在 \(v\) 的子树中,由于一个子树在 DFS 序上是连续的,子树的限制就转化为区间的限制了,主席树处理即可。

#include<bits/stdc++.h>
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf,obuf[1<<21],*p3=obuf;
inline char gc(){
	return p1==p2?p2=(p1=buf)+fread(buf,1,1<<21,stdin),*p1++:*p1++;
}
inline void pc(char ch){
	p3-obuf<1<<20?(*p3++=ch):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=ch);
}
inline int read(){
	int res=0;
	char ch=gc();
	while(ch<'0'||ch>'9') ch=gc();
	while(ch>='0'&&ch<='9'){
		res=(res<<1)+(res<<3)+(ch^48);
		ch=gc();
	}
	return res;
}
inline void write(int x){
	if(x<0) pc('-'),x=-x;
	if(x>9) write(x/10);
	pc(x%10^48);
}
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10;
int n,m,q,h[N],ne[N],e[N],idx,f[N][20],dep[N],g[N][20],d[N],in[N],out[N],num,tot,root[N],ls[N];
pii line[N];
struct node{
	int ls,rs,sum;
}tr[N<<5];
inline void add(int u,int v){
	ne[++idx]=h[u],h[u]=idx,e[idx]=v;
}
inline void dfs(int u,int fa){
	in[u]=++num;
	dep[u]=dep[fa]+1;
	f[u][0]=fa;
	for(int i=1;1<<i<dep[u];++i) f[u][i]=f[f[u][i-1]][i-1];
	for(int i=h[u];i;i=ne[i]){
		dfs(e[i],u);
	}
	out[u]=num;
}
inline void dfs1(int u){
	for(int i=h[u];i;i=ne[i]){
		dfs1(e[i]);
		if(dep[g[e[i]][0]]<dep[g[u][0]]) g[u][0]=g[e[i]][0];
	}
//	cout<<u<<" "<<g[u][0]<<"\n";
}
inline void dfs3(int u){
	d[u]=d[g[u][0]]+1;
	for(int i=h[u];i;i=ne[i]){
		dfs3(e[i]);
	}
}
inline void dfs2(int u){
	if(g[u][0]==u) g[u][0]=0;
//	cout<<u<<" "<<d[u]<<"--\n";
	for(int i=1;1<<i<d[u];++i){
		g[u][i]=g[g[u][i-1]][i-1];
//		cout<<u<<" "<<i<<" "<<g[u][i]<<"\n";
	}
	for(int i=h[u];i;i=ne[i]){
		dfs2(e[i]);
	}
}
inline int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=18;i>=0&&dep[u]>dep[v];--i){
		if(dep[u]-(1<<i)>=dep[v]) u=f[u][i];
	}
	if(u==v) return u;
	for(int i=18;i>=0;--i){
		if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
	}
	return f[u][0];
}
inline void build(int &u,int l,int r){
	u=++tot;
	if(l==r) return ;
	int mid=l+r>>1;
	build(tr[u].ls,l,mid);
	build(tr[u].rs,mid+1,r);
}
inline void mdf(int u,int &v,int l,int r,int x){
	tr[v=++tot]=tr[u];
	++tr[v].sum;
	if(l==r) return ;
	int mid=l+r>>1;
	if(x<=mid) mdf(tr[u].ls,tr[v].ls,l,mid,x);
	else mdf(tr[u].rs,tr[v].rs,mid+1,r,x);
}
inline int query(int u,int v,int L,int R,int l,int r){
	if(l<=L&&R<=r) return tr[v].sum-tr[u].sum;
	int mid=L+R>>1,res=0;
	if(l<=mid) res+=query(tr[u].ls,tr[v].ls,L,mid,l,r);
	if(r>mid) res+=query(tr[u].rs,tr[v].rs,mid+1,R,l,r);
	return res;
}
inline int ef(int x){
	int l=1,r=m,res=m+1;
	while(l<=r){
		int mid=l+r>>1;
		if(line[mid].first>=x) res=mid,r=mid-1;
		else l=mid+1;
	}
	return res;
}
inline int ef1(int x){
	int l=1,r=m,res=0;
	while(l<=r){
		int mid=l+r>>1;
		if(line[mid].first<=x) res=mid,l=mid+1;
		else r=mid-1;
	}
	return res;
}
inline int exlca(int u,int v){
	if(u==v) return 1;
	int l=lca(u,v),mu=u,mv=v,res=0;
//	cout<<u<<" "<<v<<" "<<l<<" ";
	for(int i=18;i>=0;--i){
		if(d[mu]-(1<<i)>0) mu=g[mu][i];
		if(d[mv]-(1<<i)>0) mv=g[mv][i];
	}
//	cout<<mu<<" "<<mv<<"\n";
	if(dep[mu]>dep[l]||dep[mv]>dep[l]) return -1;
	for(int i=18;i>=0;--i){
		if(d[u]-(1<<i)>0&&dep[g[u][i]]>dep[l]) u=g[u][i],res+=(1<<i);
		if(d[v]-(1<<i)>0&&dep[g[v][i]]>dep[l]) v=g[v][i],res+=(1<<i);
	}
//	cout<<res<<" ";
	res+=(u!=l)+(v!=l);
	int Lu=ef(in[u]),Ru=ef1(out[u]),Lv=ef(in[v]),Rv=ef1(out[v]);
//	cout<<u<<" "<<Lu<<" "<<Ru<<" "<<v<<" "<<Lv<<" "<<Rv<<" ";
//	cout<<res<<" "<<query(root[Lu-1],root[Ru],1,n,in[v],out[v])<<" "<<query(root[Lv-1],root[Rv],1,n,in[u],out[u])<<" ";
	if(u!=l&&v!=l&&(Lu<=Ru?query(root[Lu-1],root[Ru],1,n,in[v],out[v]):0)+(Lv<=Rv?query(root[Lv-1],root[Rv],1,n,in[u],out[u]):0)>0) --res;
	return res;
}
int main(){
	n=read();
	for(int i=2,x;i<=n;++i){
		x=read();
		add(x,i);
		g[i][0]=i;
	}
	g[1][0]=1;
	dfs(1,0);
	m=read();
	for(int i=1,x,y,l;i<=m;++i){
		x=read();y=read();
		line[i]={in[x],in[y]};
		l=lca(x,y);
		if(dep[l]<dep[g[x][0]]) g[x][0]=l;
		if(dep[l]<dep[g[y][0]]) g[y][0]=l;
	}
	sort(line+1,line+1+m);
	build(root[0],1,n);
	for(int i=1;i<=m;++i){
		ls[i]=line[i].first;
		mdf(root[i-1],root[i],1,n,line[i].second);
	}
	dfs1(1);
	dfs3(1);
	dfs2(1);
	q=read();
	for(int i=1;i<=q;++i){
		int x,y;
		x=read();y=read();
//		cout<<x<<" "<<y<<" ";
		write(exlca(x,y)),pc('\n');
	}
	fwrite(obuf,p3-obuf,1,stdout);
	return 0;
}