Problem:
Score : 2000 points

Problem Statement

You are given a connected graph with N vertices and M edges. The vertices are numbered 1 to N. The i-th edge is an undirected edge of length C_i connecting Vertex A_i and Vertex B_i.

Additionally, an odd number MOD is given.

You will be given Q queries, which should be processed. The queries take the following form:

Given in the i-th query are S_i, T_i and R_i. Print YES if there exists a path from Vertex S_i to Vertex T_i whose length is R_i modulo MOD, and print NO otherwise. A path may traverse the same edge multiple times, or go back using the edge it just used.

Here, in this problem, the length of a path is NOT the sum of the lengths of its edges themselves, but the length of the first edge used in the path gets multiplied by 1, the second edge gets multiplied by 2, the third edge gets multiplied by 4, and so on. (More formally, let L_1,...,L_k be the lengths of the edges used, in this order. The length of that path is the sum of L_i \times 2^{i-1}.)

Constraints

1 \leq N,M,Q \leq 50000

3 \leq MOD \leq 10^{6}

MOD is odd.

1 \leq A_i,B_i\leq N

0 \leq C_i \leq MOD-1

1 \leq S_i,T_i \leq N

0 \leq R_i \leq MOD-1

The given graph is connected. (It may contain self-loops or multiple edges.)

Input

Input is given from Standard Input in the following format:

N M Q MOD
A_1 B_1 C_1
\vdots
A_M B_M C_M
S_1 T_1 R_1
\vdots
S_Q T_Q R_Q

Output

Print the answers to the i-th query in the i-th line.

Sample Input 1

3 2 2 2019
1 2 1
2 3 2
1 3 5
1 3 4

Sample Output 1

YES
NO

The answer to each query is as follows:

The first query: If we take the path 1,2,3, its length is 1 \times 2^0 + 2 \times 2^1 = 5, so there exists a path whose length is 5 modulo 2019. The answer is YES.

The second query: No matter what path we take from Vertex 1 to Vertex 3, its length will never be 4 modulo 2019. The answer is NO.

Sample Input 2

6 6 3 2019
1 2 4
2 3 4
3 4 4
4 5 4
5 6 4
6 1 4
2 6 1110
3 1 1111
4 5 1112

Sample Output 2

YES
NO
NO

Sample Input 3

1 2 3 25
1 1 1
1 1 2
1 1 13
1 1 6
1 1 14

Sample Output 3

YES
YES
YES

Sample Input 4

10 15 10 15
1 2 1
2 3 6
3 4 6
2 5 1
5 6 1
4 7 6
1 8 11
2 9 6
5 10 11
9 10 11
3 6 1
2 5 1
2 7 11
9 10 11
5 6 11
1 3 5
9 8 3
7 7 7
7 10 13
4 1 10
9 3 12
10 10 14
9 2 1
6 6 5
8 8 4

Sample Output 4

YES
NO
NO
NO
NO
NO
NO
YES
YES
NO

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

//Author:xht37
#include <bits/stdc++.h>

#define ui unsigned int
#define ll long long
#define ul unsigned ll
#define ld long double

#define pi pair <int, int>
#define fi first
#define se second
#define mp make_pair

#define ls (p << 1)
#define rs (ls | 1)
#define md ((t[p].l + t[p].r) >> 1)

#define vi vector <int>
#define pb push_back
#define pq priority_queue

#define dbg(x) cerr << #x" = " << x << endl
#define debug(...) fprintf(stderr, __VA_ARGS__)

#define fl(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)

using namespace std;

namespace io {
	const int SI = 1 << 21 | 1;
	char IB[SI], *IS, *IT, OB[SI], *OS = OB, *OT = OS + SI - 1, c, ch[100];
	int f, t;
	#define gc() (IS == IT ? (IT = (IS = IB) + fread(IB, 1, SI, stdin), IS == IT ? EOF : *IS++) : *IS++)
	inline void flush() {
		fwrite(OB, 1, OS - OB, stdout), OS = OB;
	}
	inline void pc(char x) {
		*OS++ = x;
		if (OS == OT) flush();
	}

	template <class I>
	inline void rd(I &x) {
		for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + (c & 15), c = gc());
		x *= f;
	}
	template <class I>
	inline void rd(I &x, I &y) {
		rd(x), rd(y);
	}
	template <class I>
	inline void rd(I &x, I &y, I &z) {
		rd(x), rd(y), rd(z);
	}
	template <class I>
	inline void rda(I *a, int n) {
		for (int i = 1; i <= n; i++) rd(a[i]);
	}
	inline void rdc(char &c) {
		for (c = gc(); c < 33 || c > 126; c = gc());
	}
	inline void rds(char *s, int &n) {
		for (c = gc(); c < 33 || c > 126; c = gc());
		for (n = 0; c >= 33 && c <= 126; s[++n] = c, c = gc());
		s[n+1] = '\0';
	}
	inline void rds(string &s) {
		for (c = gc(); c < 33 || c > 126; c = gc());
		for (s.clear(); c >= 33 && c <= 126; s.pb(c), c = gc());
	}

	template <class I>
	inline void print(I x, char k = '\n') {
		if (!x) pc('0');
		if (x < 0) pc('-'), x = -x;
		while (x) ch[++t] = x % 10 + '0', x /= 10;
		while (t) pc(ch[t--]);
		pc(k);
	}
	template <class I>
	inline void print(I x, I y) {
		print(x, ' '), print(y);
	}
	template <class I>
	inline void print(I x, I y, I z) {
		print(x, ' '), print(y, ' '), print(z);
	}
	template <class I>
	inline void printa(I *a, int n) {
		for (int i = 1; i <= n; i++) print(a[i], " \n"[i==n]);
	}
	inline void printc(char c) {
		pc(c);
	}
	inline void prints(char *s, int n) {
		for (int i = 1; i <= n; i++) pc(s[i]);
		pc('\n');
	}
	inline void prints(string s) {
		int n = s.length();
		while (t < n) pc(s[t++]);
		pc('\n'), t = 0;
	}
	struct Flush {
		~Flush() {
			flush();
		}
	} flusher;
}
using io::rd;
using io::rda;
using io::rdc;
using io::rds;
using io::print;
using io::printa;
using io::printc;
using io::prints;

const int N = 5e4 + 7, M = 1e6 + 7;
int n, m, q, P, a[N], b[N], c[N], f[N*6+1], g, z;
bool v[2][M];

inline int get(int x) {
	return x == f[x] ? x : f[x] = get(f[x]);
}

inline void merge(int x, int y) {
	f[get(x)] = get(y);
}

inline int id(int x, int y, int z) {
	return (x - 1) * 6 + y * 3 + z;
}

int main() {
    rd(n, m, q), rd(P);
    for (int i = 1; i <= m; i++)
		rd(a[i], b[i], c[i]), g = __gcd(g, abs(c[i] - c[1]));
	g = g ? g : P, P = __gcd(P, 3 * g), z = c[1] % g;
    for (int i = 1; i <= 6 * n; i++) f[i] = i;
    for (int i = 1; i <= m; i++) {
        int w = (c[i] - z) / g;
        for (int p = 0; p < 2; p++)
            for (int q = 0; q < 3; q++)
                merge(id(a[i], p, q), id(b[i], 1 - p, (2 * q + w) % 3)),
                merge(id(b[i], p, q), id(a[i], 1 - p, (2 * q + w) % 3));
    }
    for (int i = 0, j = z; i < P << 1; i++, (j <<= 1) %= P) v[i&1][j] = 1;
    for (int i = 1, s, t, r; i <= q; i++) {
        rd(s, t, r);
        bool ans = 0;
        for (int p = 0; p < 2; p++)
            for (int q = 0; q < 3; q++)
                if (get(id(t, 0, 0)) == get(id(s, p, q)))
                    ans |= v[p][(r+z+(3-q)*g)%P];
        prints(ans ? "YES" : "NO");
    }
    return 0;
}