【数论+并查集】Walk on Graph

    科技2022-07-11  84

    题目

    有一张n个点m条边的无向连通图G,每条边有长度ci,有一个人在上面走 有q组询问,每组询问给出si,ti,ri,表示问你是否存在一条从si出发到ti结束长度为ri%Mod的路径 注意这里的路径长度是∑ci*2^i n,m,q<=50000,Mod<=1000000且Mod为奇数

    思路

    考虑把这个过程倒过来,这样每走一次就会变成 2 x + w 2x + w 2x+w

    朴素做法是判断到某个点,值为 x x x 是否可行,考虑寻找一些性质来优化这个做法。

    不难发现直接做的话是单向边,这样处理起来比较困难。

    考虑一条边 ( u , v , w ) (u, v, w) (u,v,w),如果在这条边上进行左右横跳的话,可以从 ( u , x ) (u, x) (u,x) 转移到 ( v , 2 x + w ) (v, 2x + w) (v,2x+w),即一个状态有唯一后继。同时因为模数为奇数,这一过程是可逆的,所以一个状态有唯一前驱。因此这会形成一个环。我们不断在这个环上走,可以从 ( v , 2 x + w ) (v, 2x + w) (v,2x+w) 走到 ( u , x ) (u, x) (u,x)。因此可达性是双向的。

    考虑一个点的某两条出边 ( a , b , w 1 ) , ( a , c , w 2 ) (a, b, w_1), (a, c, w_2) (a,b,w1),(a,c,w2),那么可以得到状态 ( a , 4 x + 3 w 1 ) , ( a , 4 x + 3 w 2 ) (a, 4x + 3w_1), (a, 4x + 3w_2) (a,4x+3w1),(a,4x+3w2),因此 ( a , x ) (a, x) (a,x) ( a , x + 3 ( w 1 − w 2 ) ) (a, x + 3(w_1 - w_2)) (a,x+3(w1w2)) 是互相可达的。显然这个连通块中任意一个点 p p p 都满足 ( p , x ) (p, x) (p,x) ( p , x + 3 ( w 1 − w 2 ) ) (p, x + 3(w_1 - w_2)) (p,x+3(w1w2)) 是互相可达的。

    考虑如果一对边边权的差为 d d d,那么我可以让 ( p , x ) (p,x) (p,x) 到达 ( p , x + 3 d ) (p, x +3d) (p,x+3d) 。证明考虑从一条边到另外一条边的路径,不难用中间的点来得到这个差。

    因此设所有边两两之差的最大公约数为 d d d,设 g = ( M O D , 3 d ) g = (MOD, 3d) g=(MOD,3d),那么 ( p , x ) (p, x) (p,x) ( p , x + g ) (p, x + g) (p,x+g) 都是可以互相到达的。

    注意到此时任意一条边的边权为 k d + r kd + r kd+r。先考虑一下 r = 0 r = 0 r=0 怎么做。此时任意一个点的状态都可以表示为 t d td td,我们可以把值对 g g g 取模,因此我们只关心 t t t 3 3 3 取模后的余数。然后就是一个点数只有 3 n 3n 3n 的图判断连通性,直接并查集维护就行了。

    现在考虑 r ≠ 0 r \neq 0 r=0 的情形。注意到所有边的 r r r 都是相同的,最终路径的权值是 ∑ i 2 i ( k i d + r ) = k d + ( 2 l − 1 ) r \sum_{i} 2^i (k_i d + r) = kd + (2^l- 1) r i2i(kid+r)=kd+(2l1)r 。现在比较难处理的问题是 2 l − 1 2^l - 1 2l1。考虑左后横跳可以在不改变 k m o d    3 k\mod 3 kmod3 的情况下使得 l l l 增加 2。因此枚举 k k k l l l 的奇偶性,判断是否存在一个 l l l 使得 k d + ( 2 l − 1 ) r = R kd + (2^l - 1) r = R kd+(2l1)r=R。现在状态数只有 6 n 6n 6n 并查集维护即可。

    代码

    #include<bits/stdc++.h> using namespace std; const int N=1e6+77; int n,m,q,mod,s,t,r,u[N],v[N],c[N],g,fa[N]; bool can[2][N]; int Id(int x,int y,int z) { return (x-1)*6+y*3+z; } int get(int x) { return fa[x]==x?x:fa[x]=get(fa[x]); } int gcd(int x,int y) { if(y==0) return x; return gcd(y,x%y); } void link(int x,int y) { x=get(x);y=get(y); if(x==y) return; fa[x]=y; } int main() { scanf("%d%d%d%d",&n,&m,&q,&mod); for(int i=1; i<=m; i++) { scanf("%d%d%d",&u[i],&v[i],&c[i]); g=gcd(g,abs(c[i]-c[1])); } if(!g) g=mod;mod=gcd(mod,3*g);int z=c[1]%g; for(int i=0; i<=6*n; i++) fa[i]=i; for(int i=1; i<=m; i++) { int w=(c[i]-z)/g; for(int p=0; p<=1; p++) for(int q=0; q<=2; q++) { link(Id(u[i],p,q),Id(v[i],1-p,(2*q+w)%3)); link(Id(v[i],p,q),Id(u[i],1-p,(2*q+w)%3)); } } for(int i=0,j=z;i<mod<<1;i++,(j<<=1)%=mod) can[i&1][j]=1; for(;q;q--) { scanf("%d%d%d",&s,&t,&r); int ret=0; for(int p=0; p<=1; p++) for(int q=0; q<=2; q++) if(get(Id(t,0,0))==get(Id(s,p,q))) ret|=can[p][(r+z+(3-q)*g)%mod]; puts(ret?"YES":"NO"); } }
    Processed: 0.010, SQL: 8