#include <bits/stdc++.h>
using namespace std;
int repr(vector<int>& fath, int x) {
  if (fath[x] < 0) return x;
  return fath[x] = repr(fath, fath[x]);
}
void merge(vector<int>& fath, vector<set<int> >& reach, int x, int y) {
  x = repr(fath, x);
  y = repr(fath, y);
  if (x == y) return;
  if (reach[x].size() > reach[y].size()) swap(x, y);
  for (set<int>::iterator it = reach[x].begin(); it != reach[x].end(); ++it) {
    reach[y].insert(*it);
  }
  reach[x].clear();
  fath[x] = y;
}
void add_edge(vector<map<int, int> >& col_edge, vector<int>& fath,
              vector<set<int> >& reach, int x, int y, int z) {
  reach[repr(fath, x)].insert(y);
  reach[repr(fath, y)].insert(x);
  if (col_edge[y].find(z) != col_edge[y].end()) {
    merge(fath, reach, x, col_edge[y][z]);
  } else {
    col_edge[y][z] = x;
  }
  if (col_edge[x].find(z) != col_edge[x].end()) {
    merge(fath, reach, y, col_edge[x][z]);
  } else {
    col_edge[x][z] = y;
  }
}
int main() {
  ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
  int n, m, c, q;
  cin >> n >> m >> c >> q;
  vector<map<int, int> > col_edge(n);
  vector<int> fath(n, -1);
  vector<set<int> > reach(n);
  for (int i = 0; i < n; ++i) {
    reach[i].insert(i);
  }
  for (int i = 0; i < m; ++i) {
    int x, y, z;
    cin >> x >> y >> z;
    --x, --y, --z;
    add_edge(col_edge, fath, reach, x, y, z);
  }
  for (; q > 0; --q) {
    char type;
    cin >> type;
    if (type == '+') {
      int x, y, z;
      cin >> x >> y >> z;
      --x, --y, --z;
      add_edge(col_edge, fath, reach, x, y, z);
    } else {
      int x, y;
      cin >> x >> y;
      --x, --y;
      if (reach[repr(fath, x)].count(y) > 0) {
        cout << "Yes" << endl;
      } else {
        cout << "No" << endl;
      }
    }
  }
}
