#include <bits/stdc++.h>
#include <type_traits>
using namespace std;

using ll=int64_t;
#define int ll

#define FOR(i,a,b) for(int i=int(a);i<int(b);i++)
#define REP(i,b) FOR(i,0,b)
#define MP make_pair
#define PB push_back
#define EB emplace_back
#define ALL(x) x.begin(),x.end()
auto& errStream=cerr;
#ifdef LOCAL
#define cerr (cerr<<"-- line "<<__LINE__<<" -- ")
#else
class CerrDummy{}cerrDummy;
template<class T>
CerrDummy& operator<<(CerrDummy&cd,const T&){
	return cd;
}
using charTDummy=char;
using traitsDummy=char_traits<charTDummy>;
CerrDummy& operator<<(CerrDummy&cd,basic_ostream<charTDummy,traitsDummy>&(basic_ostream<charTDummy,traitsDummy>&)){
	return cd;
}
#define cerr cerrDummy
#endif
#define REACH cerr<<"reached"<<endl
#define DMP(x) cerr<<#x<<":"<<x<<endl
#define ZERO(x) memset(x,0,sizeof(x))
#define ONE(x) memset(x,-1,sizeof(x))

using pi=pair<int,int>;
using vi=vector<int>;
using ld=long double;

template<class T,class U>
ostream& operator<<(ostream& os,const pair<T,U>& p){
	os<<"("<<p.first<<","<<p.second<<")";
	return os;
}

template<class T>
ostream& operator <<(ostream& os,const vector<T>& v){
	os<<"{";
	REP(i,(int)v.size()){
		if(i)os<<",";
		os<<v[i];
	}
	os<<"}";
	return os;
}

template<int i,class T>
void print_tuple(ostream&,const T&){
}

template<int i,class T,class H,class ...Args>
void print_tuple(ostream&os,const T&t){
	if(i)os<<",";
	os<<get<i>(t);
	print_tuple<i+1,T,Args...>(os,t);
}

template<class ...Args>
ostream& operator<<(ostream&os,const tuple<Args...>&t){
	os<<"(";
	print_tuple<0,tuple<Args...>,Args...>(os,t);
	return os<<")";
}

ll read(){
	ll i;
	scanf("%"  SCNd64,&i);
	return i;
}

void printSpace(){
	printf(" ");
}

void printEoln(){
	printf("\n");
}

void print(ll x,int suc=1){
	printf("%" PRId64,x);
	if(suc==1)
		printEoln();
	if(suc==2)
		printSpace();
}

template<class T>
void print(const vector<T>&v){
	REP(i,v.size())
		print(v[i],i==int(v.size())-1?1:2);
}

string readString(){
	static char buf[3341000];
	scanf("%s",buf);
	return string(buf);
}

char* readCharArray(){
	static char buf[3341000];
	static int bufUsed=0;
	char* ret=buf+bufUsed;
	scanf("%s",ret);
	bufUsed+=strlen(ret)+1;
	return ret;
}

template<class T,class U>
void chmax(T& a,U b){
	if(a<b)
		a=b;
}

template<class T,class U>
void chmin(T& a,U b){
	if(b<a)
		a=b;
}

template<class T>
T Sq(const T& t){
	return t*t;
}

#define CAPITAL
void Yes(bool ex=true){
	#ifdef CAPITAL
	cout<<"YES"<<endl;
	#else
	cout<<"Yes"<<endl;
	#endif
	if(ex)exit(0);
}
void No(bool ex=true){
	#ifdef CAPITAL
	cout<<"NO"<<endl;
	#else
	cout<<"No"<<endl;
	#endif
	if(ex)exit(0);
}

const ll infLL=LLONG_MAX/3;

#ifdef int
const int inf=infLL;
#else
const int inf=INT_MAX/2-100;
#endif

constexpr ll TEN(int n){
	return n==0?1:TEN(n-1)*10;
}

template<class T>
vector<T> Uniqued(const vector<T>&vv){
	auto v(vv);
	sort(ALL(v));
	v.erase(unique(ALL(v)),v.end());
	return v;
}
template<class T>
void MakeUniqued(vector<T>&v){
	sort(ALL(v));
	v.erase(unique(ALL(v)),v.end());
}

int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}

int lcm(int a,int b){
	return a/gcd(a,b)*b;
}

int extgcd(int a,int b,int&x,int&y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}else{
		int g=extgcd(b,a%b,y,x);
		y-=a/b*x;
		return g;
	}
}

struct Edge{
	int to,cost;
};

struct Query{
	int s,t,v;
};

struct VerySlow{
	int n;
	vector<vector<Edge>> g;
	int p;
	VerySlow(const vector<vector<Edge>>&gg,const int pp):
	n(gg.size()),g(gg),p(pp){
	}
	static const int Size=2019;
	bool vis[Size][Size];
	int gV,gD;
	bool dfs(int v,int d){
		if(v==gV&&d==gD)
			return true;
		if(vis[v][d])
			return false;
		vis[v][d]=true;
		for(auto e:g[v])
			if(dfs(e.to,(d*2+e.cost)%p))
				return true;
		return false;
	}
	bool Query(int src,int dst,int v){
		ZERO(vis);
		gV=src;
		gD=v;
		return dfs(dst,0);
	}
};

struct Slow{
	int n;
	vector<vector<Edge>> g;
	int p;
	int s;
	vi dep,ord;
	Slow(const vector<vector<Edge>>&gg,const int pp):
	n(gg.size()),g(gg),p(pp){
		vi pow2{1};
		while(1){
			int nx=pow2.back()*2%p;
			if(nx==1)break;
			pow2.PB(nx);
		}
		s=pow2.size();
		dep.assign(n*s,-1);
		ord.assign(n*s,-1);
		
		vi st;
		const auto Reach=[&](int i,int j,int d){
			if(dep[i*s+j]!=-1)
				return;
			dep[i*s+j]=d;
			st.PB(i*s+j);
		};
		Reach(0,0,0);
		while(!st.empty()){
			int w=st.back();st.pop_back();
			int i=w/s,j=w%s;
			for(auto e:g[i]){
				int nx=(dep[w]+e.cost*pow2[j])%p;
				Reach(e.to,(j+1)%s,nx);
			}
		}
		
		REP(i,n)REP(j,s)for(auto e:g[i])if(dep[i*s+j]!=-1){
			int w=(dep[i*s+j]+e.cost*pow2[j]-dep[e.to*s+(j+1)%s])%p;
			if(w<0)w+=p;
			p=gcd(w,p);
		}
		REP(i,n)REP(j,s)if(dep[i*s+j]!=-1)
			dep[i*s+j]%=p;
	}
	bool Query(int src,int dst,int v){
		if(dep[src*s]!=-1)
			v=(v+dep[src*s])%p;
		else
			v=(v*2+dep[src*s+1])%p;
		REP(j,s)if(dep[dst*s+j]==v)
			return true;
		return false;
	}
};

struct UnionFind{
	vi rank,par;
	void Init(int n){
		rank.assign(n,0);
		par.assign(n,-1);
	}
	int Find(int i){
		return par[i]==-1?i:(par[i]=Find(par[i]));
	}
	bool Same(int a,int b){
		return Find(a)==Find(b);
	}
	bool Unite(int a,int b){
		a=Find(a);
		b=Find(b);
		if(a==b)
			return false;
		if(rank[a]<rank[b])
			swap(a,b);
		par[b]=a;
		if(rank[a]==rank[b])
			rank[a]++;
		return true;
	}
};

struct Solver{
	int n;
	vector<vector<Edge>> g;
	int p;
	int ord,q,gcd_pq,inv_q,len;
	vi lg2;
	UnionFind uf;
	Solver(const vector<vector<Edge>>&gg,const int pp):
	n(gg.size()),g(gg),p(pp){
		{
			int base=g[0][0].cost;
			REP(i,n)
				for(auto e:g[i])
					p=gcd(p,3*(e.cost-base)%p+p);
			REP(i,n)
				for(auto&e:g[i])
					e.cost%=p;
		}
		if(p==1)return;
		if(p%3==0){
			int w=p/3;
			q=g[0][0].cost%w;
			uf.Init(n*6);
			REP(i,n)REP(j,2)REP(k,3)for(auto e:g[i]){
				int c=e.cost/w;
				uf.Unite((i*2+j)*3+k,(e.to*2+(j^1))*3+(k+c*(j+1))%3);
			}
		}else{
			q=g[0][0].cost;
			uf.Init(n*2);
			REP(i,n)REP(k,2)for(auto e:g[i])
				uf.Unite(i*2+k,e.to*2+(k^1));
		}
		int tmp;
		gcd_pq=extgcd(q,p,inv_q,tmp);
		len=p/gcd_pq;
		assert(abs(inv_q)<len);
		if(inv_q<0)inv_q+=len;
		lg2.resize(len,-1);
		if(len==1){
			lg2[0]=0;
			ord=1;
		}else{
			int cur=1,i=0;
			do{
				lg2[cur]=i;
				cur=cur*2%len;
				i++;
			}while(cur!=1);
			ord=i;
		}
	}
	bool Query(int s,int t,int v){
		if(p==1)return true;
		if(p%3==0){
			int w=p/3;
			bool ans=false;
			REP(k,3){
				int v2=v-k*w;
				if(v2<0)v2+=p;
				if(v2%gcd_pq)
					continue;
				v2=(v2/gcd_pq*inv_q+1)%len;
				if(lg2[v2]==-1)
					continue;
				if(ord%2==0){
					ans|=uf.Same(s*6,(t*2+lg2[v2]%2)*3+k);
				}else{
					ans|=uf.Same(s*6,(t*2)*3+k)|uf.Same(s*6,(t*2+1)*3+k);
				}
			}
			return ans;
		}else{
			if(v%gcd_pq)
				return false;
			v=(v/gcd_pq*inv_q+1)%len;
			if(lg2[v]==-1)
				return false;
			bool ans=false;
			if(ord%2==0){
				ans=uf.Same(s*2,t*2+lg2[v]%2);
			}else{
				ans=uf.Same(s*2,t*2)|uf.Same(s*2,t*2+1);
			}
			return ans;
		}
	}
};

struct Solver2{
	int n;
	vector<vector<Edge>> g;
	int p;
	int ord,q;
	vi lg2;
	UnionFind uf;
	Solver2(const vector<vector<Edge>>&gg,const int pp):
	n(gg.size()),g(gg),p(pp){
		{
			int base=g[0][0].cost;
			REP(i,n)
				for(auto e:g[i])
					p=gcd(p,3*(e.cost-base)%p+p);
			REP(i,n)
				for(auto&e:g[i])
					e.cost%=p;
		}
		if(p==1)return;
		if(p%3==0){
			int w=p/3;
			q=g[0][0].cost%w;
			uf.Init(n*6);
			REP(i,n)REP(j,2)REP(k,3)for(auto e:g[i]){
				int c=e.cost/w;
				uf.Unite((i*2+j)*3+k,(e.to*2+(j^1))*3+(k*2+c)%3);
			}
		}else{
			q=g[0][0].cost;
			uf.Init(n*2);
			REP(i,n)REP(k,2)for(auto e:g[i])
				uf.Unite(i*2+k,e.to*2+(k^1));
		}
		lg2.resize(p,-1);
		if(q==0){
			lg2[0]=0;
			ord=1;
		}else{
			int cur=q,i=0;
			do{
				lg2[cur]=i;
				cur=cur*2%p;
				i++;
			}while(cur!=q);
			ord=i;
		}
	}
	bool Query(int s,int t,int v){
		if(p==1)return true;
		if(p%3==0){
			int w=p/3;
			bool ans=false;
			REP(k,3){
				int v2=(v-k*w+q)%p;
				if(v2<0)v2+=p;
				if(lg2[v2]==-1)
					continue;
				if(ord%2==0){
					ans|=uf.Same((s*2+lg2[v2]%2)*3+k,t*6);
				}else{
					ans|=uf.Same((s*2)*3+k,t*6)|uf.Same((s*2+1)*3+k,t*6);
				}
			}
			return ans;
		}else{
			v=(v+q)%p;
			if(lg2[v]==-1)
				return false;
			bool ans=false;
			if(ord%2==0){
				ans=uf.Same(s*2+lg2[v]%2,t*2);
			}else{
				ans=uf.Same(s*2,t*2)|uf.Same(s*2+1,t*2);
			}
			return ans;
		}
	}
};

signed main(){
	int n=read(),m=read(),q=read(),p=read();
	vector<vector<Edge>> g(n);
	REP(i,m){
		int a=read()-1,b=read()-1,c=read();
		g[a].PB(Edge{b,c});
		g[b].PB(Edge{a,c});
	}
	Solver2 sol(g,p);
	REP(i,q){
		int s=read()-1,t=read()-1,r=read()%p;
		bool ans=sol.Query(s,t,r);
		if(ans)Yes(0);
		else No(0);
	}
}


Measured memory_bytes: 19968