#include <bits/stdc++.h>
#pragma GCC optimize("-O2")
using namespace std;
void err(istream_iterator<string> it) { cerr << endl; }
template <typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
  cerr << *it << " = " << a << "\t";
  err(++it, args...);
}
template <typename T1, typename T2>
ostream& operator<<(ostream& c, pair<T1, T2>& v) {
  c << "(" << v.first << "," << v.second << ")";
  return c;
}
template <template <class...> class TT, class... T>
ostream& operator<<(ostream& out, TT<T...>& c) {
  out << "{ ";
  for (auto& x : c) out << x << " ";
  out << "}";
  return out;
}
const int LIM = 1e5 + 5, MOD = 1e9 + 7;
int t, n, m, k, x, y, w, c, q;
map<int, vector<int> > v[LIM];
set<int> e[LIM];
struct dsu {
  vector<int> par, rk;
  void reset(int n) {
    rk.assign(n, 1);
    par.resize(n);
    iota(par.begin(), par.end(), 0);
    for (int i = 0; i < n; ++i) e[i].insert(i);
  }
  int getpar(int i) { return (par[i] == i) ? i : (par[i] = getpar(par[i])); }
  bool con(int i, int j) { return getpar(i) == getpar(j); }
  bool join(int i, int j) {
    i = getpar(i), j = getpar(j);
    if (i == j) return 0;
    if (rk[i] > rk[j]) {
      par[j] = i;
      rk[i] += rk[j];
      for (auto& it : e[j]) e[i].insert(it);
      e[j].clear();
    } else {
      par[i] = j;
      rk[j] += rk[i];
      for (auto& it : e[i]) e[j].insert(it);
      e[i].clear();
    }
    return 1;
  }
} d;
signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> m >> c >> q;
  d.reset(n);
  for (int i = 0; i < m; ++i) {
    cin >> x >> y >> w;
    --x, --y;
    v[x][w].push_back(y);
    v[y][w].push_back(x);
    e[d.getpar(x)].insert(y);
    d.join(v[x][w][0], y);
    e[d.getpar(y)].insert(x);
    d.join(v[y][w][0], x);
  }
  char ch;
  for (int i = 0; i < q; ++i) {
    cin >> ch >> x >> y;
    --x, --y;
    if (ch == '?') {
      bool ok = e[d.getpar(x)].find(y) != e[d.getpar(x)].end();
      if (ok)
        cout << "Yes\n";
      else
        cout << "No\n";
    } else {
      cin >> w;
      v[x][w].push_back(y);
      v[y][w].push_back(x);
      e[d.getpar(x)].insert(y);
      d.join(v[x][w][0], y);
      e[d.getpar(y)].insert(x);
      d.join(v[y][w][0], x);
    }
  }
  return 0;
}
