首先考虑结论:(u) 和 (v) 必须在同一个联通分量里面,然后从 (u) 沿任意路径走到 (v) ,设剩下的时间为 (t) ,若 (t) 是当前联通分量中所有环的长度的 (gcd) 的倍数,那么答案是 (1) ,否则是 (0) 。
对于其正确性:若存在满足条件的路径,必定是通过一条链,并路过几个环。由于边正反走的权值互为相反数,那么可以做到经过任意一个环,又由于裴蜀定理那套理论,所以结论是正确的。
然后可以维护并查集,并记录 (u) 与 (fa_u) 之间的边权 (dis_u),(fa_u) 指并查集上的 (fa),并在路径压缩的时候动态更改,那么每次查询的时候可以得到一个点到根的路径。同时可以发现 (u) 和 (v) 之间实际的距离就是 (dis_u-dis_v) ,并在连边的时候做到快速更新。
Code:
// namespace maze_io
#define N 100005
int fa[N],n,Q,k,t;
ll ans[N],dis[N];
int find(int u)
{
if(fa[u]==u) return u;
int tmp=fa[u];
fa[u]=find(fa[u]);
dis[u]+=dis[tmp];
return fa[u];
}
ll gcd(ll x,ll y)
{
return y==0?x:gcd(y,x%y);
}
signed main()
{
maze_io::get_args(&n,&Q,&k,&t);
for(int i=1;i<=n;i++) fa[i]=i;
for(int _=1;_<=Q;_++)
{
int opt,u,v; ll w;
maze_io::get_line(&opt,&u,&v,&w);
if(!opt)
{
int U=find(u),V=find(v);
if(U==V)
{
ll R=dis[u]-dis[v]-w;
ans[U]=gcd(ans[U],abs(R));
}
else
{
fa[U]=V;
dis[U]=dis[v]+w-dis[u];
ans[V]=gcd(ans[U],ans[V]);
}
}
else
{
int U=find(u),V=find(v);
if(U!=V) maze_io::put_ans(0);
else
{
ll R=abs(w-dis[u]+dis[v]);
if(ans[V]==0) maze_io::put_ans(R==0);
else maze_io::put_ans(R%ans[V]==0);
}
}
}
return 0;
}