#include <bits/stdc++.h>
using namespace std;
struct Dinic {
  struct Edge {
    int to, flow, next;
  };
  vector<Edge> edges;
  vector<int> head, act, h;
  int S, D;
  void AddEdge(int from, int to, int f, int rev_f = 0) {
    edges.push_back({to, f, (int)edges.size()});
    swap(edges.back().next, head[from]);
    edges.push_back({from, rev_f, (int)edges.size()});
    swap(edges.back().next, head[to]);
  }
  bool bfs() {
    fill(h.begin(), h.end(), -1);
    h[S] = 0;
    vector<int> q = {S};
    for (int it = 0; it < q.size() && h[D] == -1; it++) {
      int nod = q[it];
      for (int i = head[nod]; i != -1; i = edges[i].next)
        if (edges[i].flow && h[edges[i].to] == -1)
          h[edges[i].to] = 1 + h[nod], q.push_back(edges[i].to);
    }
    return h[D] != -1;
  }
  int dfs(int nod, int flow) {
    if (flow == 0 || nod == D) return flow;
    while (act[nod] != -1) {
      Edge& e = edges[act[nod]];
      int d;
      if (e.flow && h[e.to] == 1 + h[nod] &&
          (d = dfs(e.to, min(flow, e.flow))) != 0) {
        e.flow -= d;
        edges[act[nod] ^ 1].flow += d;
        return d;
      }
      act[nod] = edges[act[nod]].next;
    }
    return 0;
  }
  int GetFlow() {
    int f = 0;
    while (bfs()) {
      act = head;
      int d;
      while ((d = dfs(S, 1e9)) != 0) f += d;
    }
    return f;
  }
  Dinic(int dim = 0, int s = 0, int d = 0)
      : head(dim + 1, -1), h(dim + 1), S(s), D(d) {}
};
struct FlowWithMinRestrictions {
  struct Edge {
    int from, to, flowmin, flowmax, id;
  };
  vector<Edge> edges;
  int S, D, n;
  void AddEdge(int from, int to, int flowmin, int flowmax) {
    edges.push_back({from, to, flowmin, flowmax, 0});
  }
  vector<int> Solve(bool& feasible, int& flow) {
    feasible = 1;
    flow = 0;
    int news = n + 1, newd = n + 2;
    Dinic first_flow(n + 2, news, newd);
    first_flow.AddEdge(D, S, 1e9);
    int s_minime = 0;
    for (auto& i : edges) {
      if (i.flowmax < i.flowmin) {
        feasible = 0;
        return vector<int>();
      }
      s_minime += i.flowmin;
      i.id = first_flow.edges.size();
      first_flow.AddEdge(i.from, i.to, i.flowmax - i.flowmin);
      first_flow.AddEdge(news, i.to, i.flowmin);
      first_flow.AddEdge(i.from, newd, i.flowmin);
    }
    if (first_flow.GetFlow() != s_minime) {
      feasible = 0;
      return vector<int>();
    }
    Dinic curent_flow(n, S, D);
    for (auto& i : edges) {
      int dif = i.flowmax - i.flowmin;
      int passed = dif - first_flow.edges[i.id].flow;
      int nid = curent_flow.edges.size();
      curent_flow.AddEdge(i.from, i.to, first_flow.edges[i.id].flow, passed);
      i.id = nid;
    }
    curent_flow.GetFlow();
    vector<int> ans(edges.size());
    for (int i = 0; i < edges.size(); i++) {
      int cntflow = curent_flow.edges[edges[i].id ^ 1].flow + edges[i].flowmin;
      ans[i] = cntflow;
      if (edges[i].from == S) flow += cntflow;
      if (edges[i].to == S) flow -= cntflow;
    }
    return ans;
  }
  FlowWithMinRestrictions(int n = 0, int s = 0, int d = 0) : n(n), S(s), D(d) {}
};
namespace ProbD {
const int NMAX = 200010;
map<int, int> nrmx, nrmy;
FlowWithMinRestrictions flow;
pair<int, int> shields[NMAX];
int idshield[NMAX];
int n, S, D;
int difmax[NMAX];
int nr_on_poz[NMAX];
int cnt = 0;
void normalize() {
  for (int i = 0; i < n; i++)
    nrmx[shields[i].first] = nrmy[shields[i].second] = 0;
  for (auto& i : nrmx) i.second = cnt++;
  for (auto& i : nrmy) i.second = cnt++;
  S = cnt++;
  D = cnt;
  fill(difmax, difmax + cnt + 1, 1e9);
}
void solve() {
  int r, b;
  int nrc;
  cin >> n >> nrc >> r >> b;
  for (int i = 0; i < n; i++) cin >> shields[i].first >> shields[i].second;
  normalize();
  flow = FlowWithMinRestrictions(cnt, S, D);
  for (int i = 0; i < n; i++) {
    shields[i].first = nrmx[shields[i].first],
    shields[i].second = nrmy[shields[i].second];
    idshield[i] = flow.edges.size();
    nr_on_poz[shields[i].first]++, nr_on_poz[shields[i].second]++;
    flow.AddEdge(shields[i].first, shields[i].second, 0, 1);
  }
  while (nrc--) {
    int t, p, val;
    cin >> t >> p >> val;
    if (t == 1 && nrmx.find(p) != nrmx.end())
      difmax[nrmx[p]] = min(difmax[nrmx[p]], val);
    else if (t == 2 && nrmy.find(p) != nrmy.end())
      difmax[nrmy[p]] = min(difmax[nrmy[p]], val);
  }
  vector<pair<int, pair<int, int>>> verif;
  for (auto i : nrmx) {
    int nr = nr_on_poz[i.second];
    int dmax = difmax[i.second];
    int vmax = (dmax + nr) / 2;
    int vmin = max(0, (nr - dmax + 1) / 2);
    verif.push_back({(int)flow.edges.size(), {vmin, vmax}});
    flow.AddEdge(S, i.second, vmin, vmax);
  }
  for (auto i : nrmy) {
    int nr = nr_on_poz[i.second];
    int dmax = difmax[i.second];
    int vmax = (dmax + nr) / 2;
    int vmin = max(0, (nr - dmax + 1) / 2);
    verif.push_back({(int)flow.edges.size(), {vmin, vmax}});
    flow.AddEdge(i.second, D, vmin, vmax);
  }
  int f;
  bool posibil;
  auto ans = flow.Solve(posibil, f);
  if (!posibil) {
    cout << "-1\n";
    return;
  }
  for (auto i : verif)
    assert(ans[i.first] >= i.second.first && ans[i.first] <= i.second.second);
  cout << 1LL * f * min(r, b) + 1LL * (n - f) * max(r, b) << '\n';
  string s = "rb";
  if (r < b) s = "br";
  for (int i = 0; i < n; i++) cout << s[ans[idshield[i]]];
  cout << '\n';
}
}  // namespace ProbD
int main() {
  ios_base::sync_with_stdio(0);
  ProbD::solve();
  return 0;
  FILE* in = fopen("cuplaj.in", "r");
  int n, m;
  fscanf(in, "%d%d", &n, &m);
  FlowWithMinRestrictions flow(n, 1, n);
  while (m--) {
    int a, b, c, d;
    fscanf(in, "%d%d%d%d", &a, &b, &c, &d);
    flow.AddEdge(a, b, c, d);
  }
  bool feasible;
  int f;
  auto ans = flow.Solve(feasible, f);
  ofstream out("flux.out");
  out << feasible << '\n' << f << '\n';
  for (auto i : ans) out << i << ' ';
  return 0;
}
