题目
Description
给定一个 n 个点的树,相邻点的距离为 1。
q 个询问,每个询问包含五个整数: x,y,a,b,k。
含义是:在原树上新连上一条边 (x,y) ,要求判断一下从 a 点是否有距离为 k 的到 b 的路径。
注意:
每个询问是独立的,即上次询问加上的边,不能为这一次的询问所用。
这一条路径也许会重复经过某一条边或某一点。
Input
- 第 1 行: n ;
- 第 2 ⋯n 行: 每行 2个整数 u,v表示原树上有一条连接结点 u,v 的边。
- 第 n+1行:q;
- 接下来 q 行:每行五个整数: x,y,a,b,k意义见上。
Output
- 针对每个询问,如果可以输出“YES”,否则输出“NO”
输入/输出例子
输入
5
1 2
2 3
3 4
4 5
5
1 3 1 2 2
1 4 1 3 2
1 4 1 3 3
4 2 3 3 9
5 2 3 3 9
输出
YES
YES
NO
YES
NO
提示
无
解题思路
分析
这道题难处理的地方就是加 1条边这个地方很难处理,但是我们可以想一想,实际上可能的路径一共就3条。
1. a⟹b 这是最原始的路径。
2. a⟹x⟹y⟹b 这是借助 x,y 的路径
3. a⟹y⟹x⟹b 这是借助 y,x 的路径。
初始化
和普通的lca一样:
struct fy
{
int t,next;
}edge[N];
void add(int x,int y)
{
edge[++cnt].t=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
void dfs(int u,int fa)
{
d[u]=d[fa]+1,f[u][0]=fa;
for(int i=1;i<=lg[d[u]];i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].next)
if(edge[i].t!=fa)
dfs(edge[i].t,u);
}
int lca(int x,int y)
{
if(d[x]<d[y])
swap(x,y);
while(d[x]>d[y])
x=f[x][lg[d[x]-d[y]]-1];
if(x==y)
return x;
for(int i=lg[d[x]]-1;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
scanf("%d",&n);
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
dfs(1,0);
处理回路
可能有有人会问,走到 1 个点,再走回来,这个怎么办呢?我们发现走到 1 个点再回来,这样 1 次路径长度是 2。所以我们这 3 条路径当中,只要有 1 条路径满足以下两个个条件,就说明存在这样一条长度为 k 的路径。
1.路径长度≤k 这一个很显然。当长度 > k时 ,显然就是不可能的。
2.(k-路径长度)%2==0。 这就是基于往回走的做法,差值为偶,就是可以组成长度为 k 路径,如图:
它们之间的最短路径为3,差值为2,为偶数
所以可以达成:g->e->b->d ->b->d ->BOON!
代码语言就是:
int ga(int x,int y)
{
return d[x]+d[y]-d[lca(x,y)]*2;
}
bool check(int x,int k)
{
return x<=k&&(k-x)%2==0?true:false;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
int ab=ga(a,b),axyb=ga(a,x)+ga(b,y)+1,ayxb=ga(a,y)+ga(b,x)+1;
if(check(ab,k)||check(axyb,k)||check(ayxb,k))
printf("YES\n");
else
printf("NO\n");
}
及:考虑三种情况,分别check
code
#include <bits/stdc++.h>
using namespace std;
const int N=1e6;
int d[N],f[N][22],lg[N],head[N],cnt,n,m,x,y,a,b,k;
struct fy
{
int t,next;
}edge[N];
void add(int x,int y)
{
edge[++cnt].t=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
void dfs(int u,int fa)
{
d[u]=d[fa]+1,f[u][0]=fa;
for(int i=1;i<=lg[d[u]];i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].next)
if(edge[i].t!=fa)
dfs(edge[i].t,u);
}
int lca(int x,int y)
{
if(d[x]<d[y])
swap(x,y);
while(d[x]>d[y])
x=f[x][lg[d[x]-d[y]]-1];
if(x==y)
return x;
for(int i=lg[d[x]]-1;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int ga(int x,int y)
{
return d[x]+d[y]-d[lca(x,y)]*2;
}
bool check(int x,int k)
{
return x<=k&&(k-x)%2==0?true:false;
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
for(int i=1;i<=n;i++)
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
dfs(1,0);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
int ab=ga(a,b),axyb=ga(a,x)+ga(b,y)+1,ayxb=ga(a,y)+ga(b,x)+1;
if(check(ab,k)||check(axyb,k)||check(ayxb,k))
printf("YES\n");
else
printf("NO\n");
}
}