#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e5 + 5;
int n, m, c, q;
map<int, int> adj[MAX];
set<int> adj2[MAX];
int ds[MAX], h[MAX];
void init() {
  for (int i = 1; i <= n; ++i) {
    ds[i] = i;
  }
}
int find(int x) { return ds[x] == x ? x : ds[x] = find(ds[x]); }
bool merge(int x, int y) {
  x = find(x);
  y = find(y);
  if (x == y) {
    return false;
  }
  if (h[x] < h[y]) swap(x, y);
  ds[y] = x;
  if (h[x] == h[y]) ++h[x];
  for (auto u : adj2[y]) {
    adj2[x].insert(u);
  }
  return true;
}
void add_edge(int x, int y, int z) {
  if (adj[x].count(z) == 0) {
    adj[x][z] = y;
  }
  merge(adj[x][z], y);
  if (adj[y].count(z) == 0) {
    adj[y][z] = x;
  }
  merge(adj[y][z], x);
  int oldx = x, oldy = y;
  x = find(x), y = find(y);
  adj2[x].insert(oldy);
  adj2[y].insert(oldx);
}
bool query(int x, int y) {
  int oldy = y;
  x = find(x);
  y = find(y);
  if (x == y) {
    return true;
  }
  if (adj2[x].count(oldy)) {
    return true;
  }
  return false;
}
int main() {
  scanf("%d%d%d%d", &n, &m, &c, &q);
  init();
  for (int i = 0; i < m; ++i) {
    int x, y, z;
    scanf("%d%d%d", &x, &y, &z);
    add_edge(x, y, z);
  }
  while (q--) {
    char op;
    int x, y;
    scanf(" %c %d %d", &op, &x, &y);
    if (op == '?') {
      if (query(x, y)) {
        printf("Yes\n");
      } else {
        printf("No\n");
      }
    } else {
      int z;
      scanf("%d", &z);
      add_edge(x, y, z);
    }
  }
}
