CF1515G - Phoenix and Odometers

CF1515G - Phoenix and Odometers

题目大意

给定一张带权有向图,每次查询\(v,s,t\)表示从\(v\)出发并且回到\(v\),可以经过重边

判断是否存在经过路径总长\(l\)满足\(l+s\equiv 0 \pmod t\)

\[\ \]

分析

显然\(v\)只能在其自己的强连通分量里走,并且分量内部的任意一个环都是可达的

由于是模意义下,所以环的贡献可以抵消,环之间可以无限叠加

根据裴蜀定理,能够生成的数就是是\(\gcd(len_i)\)的倍数

只需预处理强连通分量内部的环,判断\(\gcd(len_i,t)|\gcd(s,t)\)即可

const int N=2e5+10;

int n,m;
struct Edge{
	int to,nxt,w;
}e[N];
int head[N],ecnt;
void AddEdge(int u,int v,int w){
	e[++ecnt]=(Edge){v,head[u],w};
	head[u]=ecnt;
}

ll G[N],S[N];
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }
int t[N],low[N],dfn,stk[N],ins[N],top,id[N],scc;
ll dis[N];

void dfs(int u){
	ins[stk[++top]=u]=1,low[u]=t[u]=++dfn;
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].to;
		if(!t[v]) {
			dis[v]=dis[u]+e[i].w;
			dfs(v),cmin(low[u],low[v]);
		} else if(ins[v]) {	
            // 不管是横边还是返祖边,长度都是dis[u]-dis[v]!!!
			cmin(low[u],t[v]);
			G[u]=gcd(G[u],dis[u]-dis[v]+e[i].w);
		}
	}
	if(low[u]==t[u]) {
		++scc;
		for(int v=-1;v!=u;) {
			ins[v=stk[top--]]=0;
			id[v]=scc,S[scc]=gcd(S[scc],G[v]);
		}
	}
}

int main(){
	n=rd(),m=rd();
	rep(i,1,m) {
		int u=rd(),v=rd(),w=rd();
		AddEdge(u,v,w);
	}
	rep(i,1,n) if(!t[i]) dfs(i);
	rep(_,1,rd()) {
		int u=rd(),s=rd(),t=rd();
		s=gcd(s,t),t=gcd(t,S[id[u]]);
		puts(s%t==0?"YES":"NO");
	}
}
posted @ 2021-05-06 11:59  chasedeath  阅读(146)  评论(0编辑  收藏  举报