图与数论
前置知识点:
强联通分量
裴蜀定理
题目描述
有一张\(n\)个点\(m\)条边的带权有向图,小马准备买了一辆车,现在小马有\(q\)辆车可以选择,每辆车都有一个里程表,里程表到达一定的值时会清零。
现在小马希望车的里程表清零,于是他有\(q\)次询问,每次询问从点\(x\)出发,里程表的初始值是\(s\)且到达\(t\)时清零,能否在回到起点时里程表恰好清零。
输入格式
一行两个整数\(n\)和\(m\)表示点数和边数
之后\(m\)行,每行三个整数\(u\),\(v\),\(w\)表示从\(u\)到\(v\)的路程是\(w\)
之后一行一个整数\(q\)表示询问数量
之后\(q\)行,每行三个整数\(x,s,t\)表示起点\(x\),初值\(s\)和到达\(t\)时清零。
输出格式
输出\(q\)行,如果可以清零输出YES否则输出NO
看到这道题的第一眼,管它什么清零不清零的,带权有向图还要回到起点,跑个tarjan再说。
因为要回到起点,所以它不能出所在的强联通分量,否则就回不来了。那它走的路径实际上等价于一个一个环拼起来的。
那么如果我们可以找到这些环的长度,根据裴蜀定理,我们只需要求出它们的最大公因数,然后判断它在模\(t\)意义下是否整除\(t-s\)即可。
至于环的长度可以在跑tarjan时顺带求出
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long N=200010;
long long n,q,m,t,s,x,tim,tmp,h[N],ha[N],dfn[N],idx[N],d[N],sta[N],top,cnt;
bool v[N],v2[N];
vector<long long>l[N];
struct edge{
long long v,w,next;
}g[N];
void add(long long u,long long v,long long w)
{
g[++tmp]={v,w,h[u]},h[u]=tmp;
}
long long gcd(long long a,long long b)
{
return b?gcd(b,a%b):a;
}
void dfs(long long x)
{
idx[x]=dfn[x]=++tim;
sta[++top]=x,v[x]=1;
for(long long i=h[x];i;i=g[i].next)
{
if(v[g[i].v])
idx[x]=min(idx[x],dfn[g[i].v]);
else if(!dfn[g[i].v])
{
dfs(g[i].v),idx[x]=min(idx[x],idx[g[i].v]);
}
}
if(idx[x]==dfn[x])
{
++cnt;
l[cnt].push_back(0);
while(sta[top]!=x)
{
ha[sta[top]]=cnt;
v[sta[top]]=0;
top--;
}
ha[sta[top]]=cnt;
v[sta[top]]=0;
top--;
}
}
void dfs2(long long x)
{
v[x]=1;
for(long long i=h[x];i;i=g[i].next)
{
if(ha[g[i].v]!=ha[x])
continue;
if(v[g[i].v])
{
l[ha[x]].push_back(g[i].w+d[x]-d[g[i].v]);
continue;
}
d[g[i].v]=d[x]+g[i].w;
dfs2(g[i].v);
}
}
int main()
{
scanf("%lld %lld",&n,&m);
for(long long i=1;i<=m;i++)
{
long long u,v,w;
scanf("%lld %lld %lld",&u,&v,&w);
add(u,v,w);
}
for(long long i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
for(long long i=1;i<=n;i++)
if(!v2[ha[i]])
v2[ha[i]]=1,dfs2(i);
for(long long i=1;i<=cnt;i++)
for(long long j=l[i].size()-2;j>=0;j--)
l[i][j]=gcd(l[i][j],l[i][j+1]);
scanf("%lld",&q);
while(q--)
{
scanf("%lld %lld %lld",&x,&s,&t);
if(!(t-s%t)&&!(l[ha[x]][0]%t)||(l[ha[x]][0]%t)&&(t-s%t)%(l[ha[x]][0]%t)==0)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}