#include <bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(false);
  size_t n, m, c, q;
  cin >> n >> m >> c >> q;
  vector<map<size_t, size_t>> adj(++n);
  vector<size_t> fa(n);
  iota(fa.begin(), fa.end(), 0);
  vector<set<size_t>> last(n);
  for (size_t i = 0; i != n; ++i) last[i].emplace(i);
  auto find = [&](const size_t& x) {
    size_t f = -1;
    vector<size_t> stack(1, x);
    while (!stack.empty()) {
      if (fa[stack.back()] == stack.back()) {
        f = stack.back();
        stack.pop_back();
      } else {
        if (~f) {
          fa[stack.back()] = f;
          stack.pop_back();
        } else {
          stack.emplace_back(fa[stack.back()]);
        }
      }
    }
    return f;
  };
  auto merge = [&](size_t x, size_t y) {
    x = find(x);
    y = find(y);
    if (x != y) {
      if (last[x].size() < last[y].size()) swap(x, y);
      last[x].insert(last[y].begin(), last[y].end());
      last[y].clear();
      fa[y] = x;
    }
  };
  auto link = [&]() {
    size_t x, y, z;
    cin >> x >> y >> z;
    auto ite = adj[x].find(z);
    if (ite != adj[x].end()) merge(y, ite->second);
    ite = adj[y].find(z);
    if (ite != adj[y].end()) merge(x, ite->second);
    adj[x][z] = y;
    adj[y][z] = x;
    last[find(x)].emplace(y);
    last[find(y)].emplace(x);
  };
  auto query = [&]() {
    size_t x, y;
    cin >> x >> y;
    x = find(x);
    cout << (last[x].find(y) != last[x].end() ? "Yes" : "No") << '\n';
  };
  while (m--) link();
  while (q--) {
    char op;
    cin >> op;
    if (op == '+')
      link();
    else
      query();
  }
}
