0628Zn

图与数论

前置知识点:
强联通分量
裴蜀定理
题目描述
有一张\(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;
}

posted on 2025-08-28 17:15  琬安与璃茗  阅读(7)  评论(0)    收藏  举报