Loading [MathJax]/jax/element/mml/optable/BasicLatin.js

[cf1515G]Phoenix and Odometers

显然这条路径只能在vi所在的强连通分量内部,不妨仅考虑这个强连通分量

对这个强连通分量dfs,得到一棵外向树(不妨以1为根)

考虑一条边(u,v,l),由于强连通,总存在一条从vu的路径,经过这条路径ti次,再经过uv这条边ti1次,即从v到达了u,且总边权l(mod ti)

由此,不妨将(v,u,l)也作为一条边加入图中,显然不影响(以下称这条边为(u,v,l)的反向边)

此时,令depx为1通过树边走到x的权值和,那么从xy通过树边及其反向边的最短路,权值和即
(deplca(x,y)depx)+(depydeplca(x,y))=depydepx
显然若没有非树边,从xy的任意一条路径(之前仅考虑最短路)权值和都为depydepx(显然每一条边都是最短路,前后项相消即可)

考虑非树边(u,v,l),若从xy的路径每经过一次(u,v,l),实际上即让边权和加l(depvdepu),最后统计所有非树边的贡献和即为总边权和

另一方面,我们显然可以经过每一条非树边任意次

由此,对每一条非树边(u,v,l)求出l(depvdepu),假设依次为a1,a2,...,as,问题即判定是否存在一组解xiN,使得sj=1xjajsi(mod ti)

根据数论知识,这显然等价于gcd,判定即可

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200005
 4 #define ll long long
 5 struct Edge{
 6     int nex,to,len;
 7 }edge[N<<1];
 8 int E,n,m,q,x,y,z,scc,head[N],head_rev[N],dfn[N],vis[N],bl[N];
 9 ll dep[N],ans[N];
10 ll gcd(ll x,ll y){
11     if (!y)return x;
12     return gcd(y,x%y);
13 }
14 void add(int x,int y,int z){
15     edge[E].nex=head[x];
16     edge[E].to=y;
17     edge[E].len=z;
18     head[x]=E++;
19 }
20 void add_rev(int x,int y,int z){
21     edge[E].nex=head_rev[x];
22     edge[E].to=y;
23     edge[E].len=z;
24     head_rev[x]=E++;
25 }
26 void dfs1(int k){
27     if (vis[k])return;
28     vis[k]=1;
29     for(int i=head[k];i!=-1;i=edge[i].nex)dfs1(edge[i].to);
30     dfn[++dfn[0]]=k;
31 }
32 void dfs2(int k,ll s){
33     if (bl[k])return;
34     bl[k]=scc;
35     dep[k]=s;
36     for(int i=head_rev[k];i!=-1;i=edge[i].nex)dfs2(edge[i].to,s+edge[i].len);
37 }
38 int main(){
39     scanf("%d%d",&n,&m);
40     memset(head,-1,sizeof(head));
41     memset(head_rev,-1,sizeof(head_rev));
42     for(int i=1;i<=m;i++){
43         scanf("%d%d%d",&x,&y,&z);
44         add(x,y,z);
45         add_rev(y,x,z);
46     }
47     for(int i=1;i<=n;i++)
48         if (!vis[i])dfs1(i);
49     for(int i=n;i;i--)
50         if (!bl[dfn[i]]){
51             scc++;
52             dfs2(dfn[i],0);
53         }
54     for(int x=1;x<=n;x++)
55         for(int j=head[x];j!=-1;j=edge[j].nex){
56             y=edge[j].to,z=edge[j].len;
57             if (bl[x]==bl[y])ans[bl[x]]=gcd(ans[bl[x]],z-(dep[x]-dep[y]));
58         }
59     scanf("%d",&q);
60     for(int i=1;i<=q;i++){
61         scanf("%d%d%d",&x,&y,&z);
62         if (y%gcd(ans[bl[x]],z)==0)printf("YES\n");
63         else printf("NO\n");
64     }
65 }
View Code
复制代码

 

posted @   PYWBKTDA  阅读(82)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示