天天看点

codeforces 1304E

题目链接

题意

有一棵树,多次询问,每次额外在树上加一条边x,y(这个不会带到下一次询问中),再问两个点a,b能否恰好走k条边到达,边可以反复走。

数据范围

树 上 节 点 数 ≤ 1 e 5 , 询 问 数 ≤ 1 e 5 , k ≤ 1 e 9 树上节点数\le 1e5,询问数\le 1e5,k\le 1e9 树上节点数≤1e5,询问数≤1e5,k≤1e9

解法

感觉非常结论。。。推了一下后发现从a走到b要么不走新边,要么从a走到x,要么从a走到y,看起来一共就3种情况,然后就对了

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n;
struct edge{
	int v,p;
}e[maxn<<1];
int h[maxn],cnt;
inline void add(int a,int b){
	e[++cnt].p=h[a];
	e[cnt].v=b;
	h[a]=cnt;
	e[++cnt].p=h[b];
	e[cnt].v=a;
	h[b]=cnt;
}
int dep[maxn],fa[maxn][20];
void dfs(int u,int f){
	fa[u][0]=f;dep[u]=dep[f]+1;
	for(int i=1;fa[u][i-1];i++)fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=h[u];i;i=e[i].p){
		int v=e[i].v;
		if(v==f)continue;
		dfs(v,u);
	}
}
inline int lca(int a,int b){
	if(dep[a]>dep[b])swap(a,b);
	for(int j=19;j>=0;j--){
		if(dep[a]<=dep[fa[b][j]]){b=fa[b][j];}
	}
	if(a==b)return a;
	for(int j=19;j>=0;j--){
		if(fa[a][j]!=fa[b][j]){
			a=fa[a][j];
			b=fa[b][j];
		}
	}
	return fa[a][0];
}
int main(){
	//freopen("5.in","r",stdin);
	//freopen("5.out","w",stdout);
	n=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		add(u,v);
	}
	dfs(1,0);
	int q=read();
	while(q--){
		int x=read(),y=read(),a=read(),b=read(),k=read();
		int l=lca(a,b);
		int dis=dep[a]+dep[b]-2*dep[l];
		if(dis<=k&&((k-dis)%2==0)){puts("YES");continue;}
		int a1=lca(a,x),a2=lca(a,y),b1=lca(b,x),b2=lca(b,y);
		int dis1=dep[a]+dep[x]-2*dep[a1]+1+dep[y]+dep[b]-2*dep[b2],dis2=dep[a]+dep[y]-2*dep[a2]+1+dep[x]+dep[b]-2*dep[b1];
		if(dis1<=k&&((k-dis1)%2==0)){puts("YES");continue;}
		if(dis2<=k&&((k-dis2)%2==0)){puts("YES");continue;}
		puts("NO");
	}
	return 0;
}