#include <bits/stdc++.h>
using namespace std;
const int N = 1000 * 100 + 10;
int par[N], n, m, c;
unordered_map<int, int> adj[N];
unordered_set<int> adj1[N];
int getPar(int root) {
  return par[root] == par[par[root]] ? par[root]
                                     : par[root] = getPar(par[root]);
}
void Union(int v, int u) {
  v = getPar(v), u = getPar(u);
  if (v == u) return;
  if (adj1[v].size() < adj1[u].size()) swap(v, u);
  par[u] = par[v];
  for (auto it : adj1[u]) adj1[v].insert(it);
}
void add(int v, int u, int c) {
  if (adj[u][c]) Union(v, adj[u][c]);
  if (adj[v][c]) Union(u, adj[v][c]);
  int pv = getPar(v), pu = getPar(u);
  adj[v][c] = pu, adj[u][c] = pv;
  adj1[pv].insert(u), adj1[pu].insert(v);
}
bool check(int v, int u) {
  int pv = getPar(v), pu = getPar(u);
  return pv == pu || adj1[pv].count(u);
}
int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int Q;
  cin >> n >> m >> c >> Q;
  for (int i = 1; i <= n; i++) par[i] = i;
  for (int i = 1, v, u, z; i <= m; i++) {
    cin >> v >> u >> z;
    add(v, u, z);
  }
  while (Q--) {
    char c;
    int x, y, z;
    cin >> c >> x >> y;
    if (c == '?')
      cout << (check(x, y) ? "Yes" : "No") << '\n';
    else {
      cin >> z;
      add(x, y, z);
    }
  }
  return 0;
}
