Phoenix and Odometers
题解
由于他需要求的是
v
v
v的回路,所以我们可以先想到将原图进行缩点,对于每个连通块单独进行处理。
对于每个连通块内部,它的所有环都是可以被重复走很多遍的。
设它所有环的长度为
a
1
,
a
2
,
.
.
.
,
a
k
a_1,a_2,...,a_k
a1,a2,...,ak那么我最后走过的总长度可以表示为
p
1
a
1
+
p
2
a
2
+
.
.
.
+
p
k
a
k
p_1a_1+p_2a_2+...+p_ka_k
p1a1+p2a2+...+pkak
在模
t
t
t的意义下,所有是
(
a
1
,
a
2
,
a
3
,
.
.
.
,
a
k
,
t
)
(a_1,a_2,a_3,...,a_k,t)
(a1,a2,a3,...,ak,t)的倍数的数都可以被表示出来。
所以我们只需要求出
(
a
1
,
a
2
,
a
3
,
.
.
.
,
a
k
,
t
)
(a_1,a_2,a_3,...,a_k,t)
(a1,a2,a3,...,ak,t)是不是
s
s
s的因数,如果是的话,
t
−
s
t-s
t−s也可以被走出来,只需要走
t
−
1
t-1
t−1遍长度为
s
s
s的路径即可。
但又要如何求出所有环的gcd呢?
我们可以先将dfs树建出来,只统计上面含一条非树边的环的长度的gcd。
如果有含多条非树边的环,它必然可以由几个只含一条非树边的环组成,不会对答案造成影响。
而对于非树边
u
−
>
v
u->v
u−>v,它的环长度就是
d
e
p
u
−
d
e
p
v
+
w
u
−
>
v
dep_u-dep_v+w_{u->v}
depu−depv+wu−>v。
再对于每个询问单独计算即可。
时间复杂度 O ( m l o g n ) O\left(mlog\,n\right) O(mlogn)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mp make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
const int INF=0x7f7f7f7f;
const int jzm=233;
const int mo=998244353;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,q,head[MAXN],tot,belong[MAXN],cnt,sta[MAXN],stak;
int dfn[MAXN],low[MAXN],idx;LL dis[MAXN],g[MAXN];
bool insta[MAXN],vis[MAXN];
struct edge{int to,nxt,paid;}e[MAXN];
void addEdge(int u,int v,int w){e[++tot]=(edge){v,head[u],w};head[u]=tot;}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
void tarjan(int u){
dfn[u]=low[u]=++idx;sta[++stak]=u;insta[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
else if(insta[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){int v;++cnt;do{v=sta[stak--];belong[v]=cnt;insta[v]=0;}while(v!=u);}
}
void dosaka(int u){
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(belong[v]^belong[u])continue;
if(!vis[v])dis[v]=dis[u]+1ll*e[i].paid,dosaka(v);
else{
LL tmp=dis[u]-dis[v]+1ll*e[i].paid;
g[belong[v]]=!g[belong[v]]?tmp:gcd(tmp,g[belong[v]]);
}
}
}
int main(){
read(n);read(m);
for(int i=1,u,v,w;i<=m;i++)read(u),read(v),read(w),addEdge(u,v,w);
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
for(int i=1;i<=n;i++)if(!vis[i])dosaka(i);
read(q);
for(int i=1;i<=q;i++){
int v,s,t;read(v);read(s);read(t);
if(!belong[v]||1ll*s%gcd(g[belong[v]],1ll*t))puts("NO");
else puts("YES");
}
return 0;
}