哇比赛的时候查不出来wtcl。。
还有,我不相信是 E 题
题意 Description
给定一个 \(n\) 个点的树,相邻点的距离为 \(1\) 。
\(q\) 个询问,每个询问包含5个整数: \(x,y,a,b,k\)。
含义是:在原树上新连上一条边 \((x,y)\) ,要求判断一下从 \(a\) 点是否有距离为 \(k\) 的到 \(b\) 的路径。
注意:
每个询问是独立的,即上次询问加上的边,不能为这一次的询问所用。
这一条路径也许会重复经过某一条边或某一点。
题解 Solution
涉及树上距离,考虑 LCA 。
对于每个询问,我们先判断一下 \(a,b\) 间有没有长度为 \(k\) 的路径,再判断一下经过边 \(x,y\) 的路径有没有长度为 \(k\) 的即可。
对于第一个:
下面的 \(\operatorname{dist}(u,v)\) 表示 \(u,v\) 的最短距离。
快速求得 \(\operatorname{dist}(u,v)\) 可以通过 LCA 来求,公式: \(\operatorname{dist}(u,v)=depth_u+depth_v-2\times depth_{\operatorname{LCA}(u,v)}\) 。其中 \(\operatorname{LCA}(u,v)\) 表示结点 \(u,v\) 的 最近公共祖先。
先求出 \(a,b\) 的最短距离 \(D = \operatorname{dist}(a,b)\)。假如说 \(D\) 与 \(k\) 的奇偶性一致且 \(k\ge D\) 的话,那么就是
YES
。为什么是奇偶性?因为如果把这条最短的路径“折一下”(1->2->3->4
折成1->2->3->2->3->4
),总长度会加二,奇偶性不变。倘若 \(k\ge D\) ,那么这样一直折下去,路径长度一定可以到达 \(k\) 。对于新加入的边,我们计算出 \(D'=\min (\operatorname{dist}(a,x)+\operatorname{dist}(b,y)+1,\operatorname{dist}(a,y)+\operatorname{dist}(b,x)+1)\),即 \(a\) 到 \(b\) 经过边 \((x,y)\) 的最短路径的长度。如果 \(D'\) 与 \(k\) 的奇偶性一致且 \(k \ge D'\) 的话就是可行的。
注意, \(D\) 或 \(D'\) 必须 \(\le k\) 否则是不成立的。因为“折”是不可以“折”负数次的。
代码 Source Code
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
int get_int()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
return f*x;
}
const int N=1e5+5;
vector<int> G[N];
int depth[N],father[N];
int maxson[N],size[N],top[N]/*link tops*/;
int n,s,m;
void DFS1(const int &now,const int &from)
{
father[now]=from,depth[now]=depth[from]+1,size[now]=1;
for(register int i=0;i<G[now].size();i++)
{
int next=G[now][i];
if(next==father[now])continue;
DFS1(next,now);
size[now]+=size[next];
if(size[maxson[now]]<size[next]||maxson[now]==0)
maxson[now]=next;
}
}
void DFS2(const int &now,const int &lktp)//link top
{
top[now]=lktp;
if(size[now]>1)DFS2(maxson[now],lktp);
for(register int i=0;i<G[now].size();i++)
{
int next=G[now][i];
if(next==father[now])continue;
if(next==maxson[now])continue;
DFS2(next,next);
}
}
inline void Prepare_Data(const int &s)
{
memset(maxson,0,sizeof(maxson));
depth[0]=0,father[s]=0;
DFS1(s,0),DFS2(s,s);
}
inline int Query_LCA(int u,int v)
{
for(;top[u]!=top[v];)
(depth[top[u]]>=depth[top[v]])?u=father[top[u]]:v=father[top[v]];
return depth[u]<depth[v]?u:v;
}
inline int Get_Dist(int u,int v)
{
int lca=Query_LCA(u,v);
return depth[v]+depth[u]-2*depth[lca];
}
signed main()
{
n=get_int(),s=1;
for(register int i=1;i<n;i++)
{
int u=get_int(),v=get_int();
G[u].push_back(v);
G[v].push_back(u);
}
Prepare_Data(s);
m=get_int();
while(m--)
{
int x=get_int(),y=get_int(),a=get_int(),b=get_int(),k=get_int();
int dis=Get_Dist(a,b);
if(dis<=k&&dis%2==k%2) {puts("YES");continue;}
dis=min(Get_Dist(a,x)+Get_Dist(b,y)+1,Get_Dist(a,y)+Get_Dist(b,x)+1);
if(dis<=k&&dis%2==k%2) puts("YES");
else puts("NO");
}
return 0;
}
- P.S. LCA部分是用树链剖分写的,倍增或 RMQ 也可以。
算法复杂度 \(\Theta (n+q\log n)\)