题目大意.
给定一个奇数
。现有一个连通无向图 ,每条边有权值。 定义一次从
到 的路径的权值为:令你一开始的持有的权值为 ,每经过一条边就把你持有的权值翻倍再加上该边的权值。 现有
组询问:是否存在从 到 的路径,其权值和 在模 意义下相等。
。
考虑反复走同一条边,则权值会依次变为
上述结论可表述为:如果有
假设现有节点
故
又
这样,对于同一个
显然,
若有边
由于
又循环节必定是
那么不断更新下去,最终的稳定状态必定满足
显然,所有边在模
可以发现,若有边
即,与
x
using namespace std;
struct node {
node *fa = this;
node *find() { return this == fa ? this : fa = fa -> find(); }
} A[50005][2][3];
void merge(node *x, node *y) {
node *fax = x -> find(), *fay = y -> find();
if (fax == fay) return;
fax -> fa = fay;
}
struct edge {
int u, v, c;
} G[50005];
int n, m_, q_, p, g, B;
bool check[2][1000005];
int main() {
scanf("%d%d%d%d", &n, &m_, &q_, &p); g = p;
for (int i = 0; i < m_; i++) {
scanf("%d%d%d", &G[i].u, &G[i].v, &G[i].c);
g = __gcd(g, abs(G[i].c - G[0].c));
}
p = __gcd(3 * g, p);
B = G[0].c % g;
for (int i = 0; i < m_; i++) {
int k = G[i].c / g;
for (int l = 0; l < 2; l++)
for (int m = 0; m < 3; m++) {
merge(A[G[i].u][l] + m, A[G[i].v][l ^ 1] + (2 * m + k) % 3),
merge(A[G[i].v][l] + m, A[G[i].u][l ^ 1] + (2 * m + k) % 3);
// printf("merge %d %d\n", l, m);
}
}
for (int i = 0, pB = B; i < p; i++, pB = (pB + pB) % p)
check[i & 1][pB] = 1;
while (q_--) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
for (int l = 0; l < 2; l++)
for (int m = 0; m < 3; m++)
if (check[l][((3 - m) * g + w + B) % p])
if (A[v][0][0].find() == A[u][l][m].find())
goto qaq;
printf("NO\n");
continue;
qaq: printf("YES\n");
}
}