#include <bits/stdc++.h>
using namespace std;
char rr[1 << 22], *csy1, *csy2;
template <class T>
inline void RI(T &t) {
  char c = (csy1 == csy2 && (csy2 = (csy1 = rr) + fread(rr, 1, 1 << 22, stdin),
                             csy1 == csy2)
                ? EOF
                : *csy1++);
  for (t = 0; c < 48 || c > 57;
       c = (csy1 == csy2 && (csy2 = (csy1 = rr) + fread(rr, 1, 1 << 22, stdin),
                            csy1 == csy2)
                ? EOF
                : *csy1++))
    ;
  for (; c > 47 && c < 58;
       c = (csy1 == csy2 && (csy2 = (csy1 = rr) + fread(rr, 1, 1 << 22, stdin),
                            csy1 == csy2)
                ? EOF
                : *csy1++))
    t = (t << 1) + (t << 3) + c - 48;
}
template <class T, typename... Args>
inline void RI(T &t, Args &...args) {
  RI(t);
  RI(args...);
}
const int Maxn = 500005;
const int Maxm = 1 << 20;
int n, m, k, q;
int qprev[Maxn];
char c[Maxn];
pair<int, char> pic[Maxn];
struct Node {
  int x, y, id;
} node[Maxn];
struct Data {
  int x;
  char rnk, c;
} sta[Maxn];
int top;
struct Union_Find {
  int fath[Maxn];
  char dis[Maxn], rnk[Maxn];
  inline void init() {
    for (register int i = 1; i <= n; ++i) {
      fath[i] = i;
    }
  }
  inline void Find(int &x, int &res) {
    res = 1;
    while (x != fath[x]) {
      res ^= dis[x];
      x = fath[x];
    }
  }
  inline void Merge(int a, int b, char c) {
    int x = a, dx, y = b, dy;
    Find(x, dx);
    Find(y, dy);
    if (x == y) return;
    if (rnk[x] > rnk[y]) swap(x, y);
    sta[top++] = (Data){x, rnk[y], c};
    rnk[y] += (rnk[x] == rnk[y]);
    fath[x] = y;
    dis[x] = (dx == dy);
  }
  inline bool check(int e) {
    int x = node[e].x, y = node[e].y;
    int dx, dy;
    Find(x, dx);
    Find(y, dy);
    if (x == y) return dx ^ dy;
    return true;
  }
} ufo[51];
vector<Node> v[Maxm];
inline void back(int x) {
  while (top > x) {
    Data t = sta[--top];
    ufo[t.c].rnk[ufo[t.c].fath[t.x]] = t.rnk;
    ufo[t.c].fath[t.x] = t.x;
    ufo[t.c].dis[t.x] = 0;
  }
}
inline void segment_modify(int i, int l, int r, int ql, int qr, int p) {
  if (l < ql || r > qr) {
    int mid = l + r >> 1;
    if (mid >= ql) segment_modify(i << 1, l, mid, ql, qr, p);
    if (mid < qr) segment_modify(i << 1 | 1, mid + 1, r, ql, qr, p);
  } else {
    v[i].push_back(node[p]);
  }
}
inline void dynamic_balance(int i, int l, int r) {
  int tm = top;
  for (int j = 0; j < v[i].size(); ++j) {
    int e = v[i][j].id;
    if (c[e]) {
      ufo[c[e]].Merge(v[i][j].x, v[i][j].y, c[e]);
    }
  }
  if (l == r) {
    int e = pic[l].first;
    char cc = pic[l].second;
    if (ufo[cc].check(e)) {
      printf("YES\n");
      c[e] = cc;
    } else {
      printf("NO\n");
    }
  } else {
    int mid = l + r >> 1;
    dynamic_balance(i << 1, l, mid);
    dynamic_balance(i << 1 | 1, mid + 1, r);
  }
  back(tm);
}
int main() {
  RI(n, m, k, q);
  for (int i = 1; i <= m; ++i) {
    RI(node[i].x, node[i].y);
    node[i].id = i;
    qprev[i] = q + 1;
  }
  for (int i = 1; i <= q; ++i) {
    int e, c;
    RI(e, c);
    pic[i] = make_pair(e, c);
    if (qprev[e] < i) {
      segment_modify(1, 1, q, qprev[e], i - 1, e);
    }
    qprev[e] = i + 1;
  }
  for (int i = 1; i <= m; ++i) {
    if (qprev[i] <= q) segment_modify(1, 1, q, qprev[i], q, i);
  }
  for (int i = 1; i <= k; ++i) {
    ufo[i].init();
  }
  dynamic_balance(1, 1, q);
  return 0;
}
