Solution
非常厉害的题捏,可惜我什么都想不到/kk
我们首先转化一下,我们对于 \(s\to t\) 计算这个长度变为 \(t\to s\) 每次加入一个 \(w\),当前权值 \(x\) 就变为 \(2x+w\)。这样就不需要在乎长度了。
所以我们可以考虑暴力设计状态 \((u,x)\) 表示到了点 \(u\) 当前长度为 \(x\),那么我们的暴力的做法就是对于这个状态暴力并查集,最后对于 \(s\to t\) 要求长度为 \(r\) 的判断判断就是是否 \((t,0)\) 与 \((s,r)\) 连通即可。显然无法通过,我们考虑仔细观察性质。
如果 \((u,x)\to (v,y)\),那么我们同样存在 \((v,y)\to (u,x)\)。
假设我们是 \(u\to v\) 间存在一个真实长度为 \(l\),值为 \(w\) 的边,那么我们存在 \(y=x2^l+w\),那么我们考虑来回走这条路径 \(t\) 次,那么值即是 \(x2^{tl}+w(\frac{2^{tl}-1}{2^l-1})\),这样的话因为模数不是质数似乎没法考虑,但是考虑到我们的路径都是长度为 \(1\) 的边构成的,所以我们不妨考虑 \(l=1\),可以发现 \(t=2\varphi(p)\) 的时候我们是满足条件的,所以我们可以证明该性质。
为了方便,我们下面用 \((u,x)\leftrightarrow (v,y)\) 来表示这种关系。
如果图中存在两条边权值分别为 \(a,b\),那么存在 \((u,x)\leftrightarrow (u,x+(a-b)\times 3)\)。
首先我们先考虑 \(u\) 连出两条权值为 \(a,b\) 的情况,我们可以发现如下关系式:
\[(u,4x+3a)\leftrightarrow (u,x)\leftrightarrow (u,4x+3b) \]因为 \(4\) 在 \(\mod p\) 的情况下是存在逆元的,所以 \(4x\) 其实在模 \(p\) 条件下可以表达任意值,所以我们可以推出:\((u,x)\leftrightarrow (u,(a-b)\times 3)\)。
我们考虑 \(u\) 与 \(v\) 存在连边的情况,假设 \(u,v\) 连边权值为 \(w\),那么我们走 \(t\) 次的话就存在:\((u,x)\leftrightarrow (v,x2^t+w(2^t-1))\) ,取 \(t=\varphi(p)\),可以发现 \((u,x)\leftrightarrow (v,x)\)。
有了以上两个条件,我们发现我们不断拓展就可以得到该性质。
有了上面的两个性质以及裴蜀定理,我们其实可以发现(\(w_i\) 是第 \(i\) 条边的边权(长度)),如果设 \(g=\gcd(w_i-w_j),i\not= j\),那么 \((u,x) \leftrightarrow (u,y)\) 当且仅当 \(x\equiv y\pmod {\gcd(3g,p)}\),所以我们完全可以把 \(p\to \gcd(3g,p)\)。那么可以发现每一个 \(w_i\) 都可以表示为 \(tg+z,t\in \mathbb{Z}\) 的形式。
我们发现,如果把 \(w_i\) 都减去 \(z\),那么可以满足都是 \(g\) 的倍数,同时如果我们设 \((u,x+z)^{'}=(u,x)\),那么对于一条边 \(w\),我们可以发现:\((u,x+z)^{'}\leftrightarrow (v,2(x+z)+w-z)^{'}=(v,2x+w+z)^{'}\),所以就跟原来的转移相同了。
同时我们观察最后的查询形式,发现现在就是查询 \((t,z)^{'}\) 与 \((s,r+z)^{'}\) 是否连通了。我们观察我们的转移,发现是 \(x\to 2x+w\) 的形式,而我们现在 \(w\) 都是 \(g\) 的倍数,而我们的 \(p\) 至多是 \(3g\),所以我们可以发现我们所有需要的 \(x\) 都可以表示为 \(z2^{2r+i}+jg,i\in \mathbb{Z},j\in \{0,1,2\}\)。而我们对于 \(u\to v\) 的权值为 \(w\) 的边,我们可以发现:\((u,x)\leftrightarrow (u,4x+3w)\leftrightarrow (u,4x)\),也就是 \(2\) 的指数奇偶性相同时是可达的。所以其实我们只需要记录 \(z2^i+jg\) 这种形式。所以只有 \(\Theta(6n)\) 个状态。所以这个时候我们就可以暴力跑并查集了,然后判一下就好了。
复杂度 \(\Theta(n\log n)\),瓶颈在于并查集。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 1000005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,m,T,mod,tot,fa[MAXN * 6],ind[MAXN][2][3],vis[2][MAXN];//ind[u][0/1][0/1/2]表示u点2^{0/1}*x+g*(0/1/2)
int findSet (int x){return fa[x] == x ? x : fa[x] = findSet (fa[x]);}
void unionSet (int u,int v){fa[findSet (u)] = findSet (v);}
bool checkit (int u,int v){return findSet (u) == findSet (v);}
struct edge{
int u,v,w;
bool operator < (const edge &p)const{return w < p.w;}
}seq[MAXN];
signed main(){
read (n,m,T,mod);
for (Int u = 1;u <= n;++ u)
for (Int p = 0;p < 2;++ p)
for (Int q = 0;q < 3;++ q) ind[u][p][q] = ++ tot;
for (Int u = 1;u <= tot;++ u) fa[u] = u;
for (Int i = 1;i <= m;++ i) read (seq[i].u,seq[i].v,seq[i].w);
sort (seq + 1,seq + m + 1);int g = mod,z;
for (Int i = 2;i <= m;++ i) g = __gcd (g,seq[i].w - seq[i - 1].w);
z = seq[1].w % g;for (Int i = 1;i <= m;++ i) seq[i].w = (seq[i].w - z) / g,seq[i].w %= 3;
mod = __gcd (3 * g,mod);
for (Int i = 1;i <= m;++ i){
int u = seq[i].u,v = seq[i].v,w = seq[i].w;
for (Int p = 0;p < 2;++ p)
for (Int q = 0;q < 3;++ q){
unionSet (ind[u][p][q],ind[v][p ^ 1][(q * 2 + w) % 3]);
unionSet (ind[v][p][q],ind[u][p ^ 1][(q * 2 + w) % 3]);
}
}
for (Int i = 0,now = z;i < mod;++ i,now = now * 2 % mod) vis[i & 1][now] = 1;
for (Int i = 1;i <= T;++ i){
int u,v,r;read (u,v,r);swap (u,v);
for (Int p = 0;p < 2;++ p)
for (Int q = 0;q < 3;++ q) if (checkit (ind[u][0][0],ind[v][p][q]) && vis[p][(r + z - g * q % mod + mod) % mod]){
puts ("YES");
goto there;
}
puts ("NO");
there:;
}
return 0;
}
标签:int,Graph,void,Walk,findSet,AGC031F,leftrightarrow,可以,我们
From: https://www.cnblogs.com/Dark-Romance/p/16811247.html