Live2D

[AGC031F] Walk on Graph

link

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;
}
posted @ 2022-10-20 20:44  Dark_Romance  阅读(25)  评论(0编辑  收藏  举报