题目链接:620E
题意:给定一颗1e5规模的边权都为1的树,接下来1e5次询问,询问间独立,每次添加一条树中不存在的边,再给定两点询问两点间的路径长度是否可以达到k,两点间的路径可以多次包含相同点,相同边,可以来回走。
这个题和我以前做过的一个题很像,忘记题号了,大概是给一个n点n边的图,询问两点最短路,只需要删掉一条边形成树,按下面那三种情况即可。
一颗树的话两点间的最短路径是唯一的,所以如果没有新的边的话,只要路径长度是小于等于询问值,且两者的奇偶性相同则说明可以达到该询问值。
如果加入一条新边,那么必然会形成一个环,删掉该边还是原来的树,于是只要考虑路径是否经过该边即可。
于是预处理lca,节点深度,就可以知道两点最短路径长度。
比如在x,y间添加一条边,询问a,b之间。
就可以分三种情况:
- a->b
- a->x,x->y,y->b
- a->y,y->x,x->b
只需要检查这三种路径长度是否有满足情况即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int fa[maxn][19];
struct Edge{
int v,next;
}edge[maxn<<1];
int head[maxn],top;
void add(int u,int v){
edge[top].v=v;
edge[top].next=head[u];
head[u]=top++;
}
int dep[maxn];
void dfs(int u,int last){
fa[u][0]=last;
dep[u]=dep[last]+1;
for(int i=1;i<18;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==last) continue;
dfs(v,u);
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=18;i>=0;--i)
if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
for(int i=18;i>=0;--i)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int getlen(int x,int y){
int lca=LCA(x,y);
return dep[x]+dep[y]-2*dep[lca];
}
bool check(int len,int k){
return len<=k&&(((len%2)^(k%2))==0);
}
int main(){
int n,u,v,x,y,a,b,k;
top=0;memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<n;++i){
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
int q;
cin>>q;
while(q--){
scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
int len=getlen(a,b);
bool f=0;
if(check(len,k)) f=1;
else{
len=getlen(x,a)+getlen(y,b)+1;
if(check(len,k)) f=1;
len=getlen(x,b)+getlen(y,a)+1;
if(check(len,k)) f=1;
}
printf("%s\n",(f?"YES":"NO"));
}
return 0;
}