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");
}
}