#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 7;
const long long MOD = (long long)1e9 + 7;
int n, m, c, q, fa[N], sz[N];
map<int, int> G[N];
set<int> ust[N];
void init() {
  for (int i = 0; i < N; ++i) {
    fa[i] = i;
    sz[i] = 1;
    ust[i].insert(i);
  }
}
int findfa(int x) { return fa[x] == x ? fa[x] : fa[x] = findfa(fa[x]); }
void mrg(int u, int v, int c) {
  int tu = G[u][c], tv = G[v][c];
  if (tv == 0) {
    G[v][c] = u;
  }
  if (tu == 0) {
    G[u][c] = v;
  }
  ust[findfa(v)].insert(u);
  ust[findfa(u)].insert(v);
  int fu, fv;
  if (tu != 0) {
    fv = findfa(v);
    fu = findfa(tu);
    if (fv != fu) {
      if (sz[fu] > sz[fv]) swap(fu, fv);
      sz[fv] += sz[fu];
      fa[fu] = fv;
      for (set<int>::iterator iter = ust[fu].begin(); iter != ust[fu].end();
           ++iter) {
        ust[fv].insert(*iter);
      }
    }
  }
  if (tv != 0) {
    fv = findfa(tv);
    fu = findfa(u);
    if (fu != fv) {
      if (sz[fu] > sz[fv]) swap(fu, fv);
      sz[fv] += sz[fu];
      fa[fu] = fv;
      for (set<int>::iterator iter = ust[fu].begin(); iter != ust[fu].end();
           ++iter) {
        ust[fv].insert(*iter);
      }
    }
  }
}
int main() {
  init();
  cin >> n >> m >> c >> q;
  for (int i = 1, u, v, c; i <= m; ++i) {
    scanf("%d%d%d", &u, &v, &c);
    mrg(u, v, c);
  }
  for (int i = 0, u, v, c; i < q; ++i) {
    static char op[2];
    scanf("%s", op);
    if (op[0] == '?') {
      scanf("%d%d", &u, &v);
      int fu = findfa(u), fv = findfa(v);
      if (fu == fv)
        puts("Yes");
      else if (ust[fu].find(v) != ust[fu].end())
        puts("Yes");
      else
        puts("No");
    } else if (op[0] == '+') {
      scanf("%d%d%d", &u, &v, &c);
      mrg(u, v, c);
    }
  }
  return 0;
}
