#include <bits/stdc++.h>
using namespace std;
namespace {
using namespace std;
template <typename flow_t = long long>
struct PushRelabel {
  struct Edge {
    int to, rev;
    flow_t f, c;
  };
  vector<vector<Edge>> g;
  vector<flow_t> ec;
  vector<Edge*> cur;
  vector<vector<int>> hs;
  vector<int> H;
  PushRelabel(int n) : g(n), ec(n), cur(n), hs(2 * n), H(n) {}
  void add_edge(int s, int t, flow_t cap, flow_t rcap = 0) {
    if (s == t) return;
    Edge a = {t, (int)g[t].size(), 0, cap};
    Edge b = {s, (int)g[s].size(), 0, rcap};
    g[s].push_back(a);
    g[t].push_back(b);
  }
  void add_flow(Edge& e, flow_t f) {
    Edge& back = g[e.to][e.rev];
    if (!ec[e.to] && f) hs[H[e.to]].push_back(e.to);
    e.f += f;
    e.c -= f;
    ec[e.to] += f;
    back.f -= f;
    back.c += f;
    ec[back.to] -= f;
  }
  flow_t max_flow(int s, int t) {
    const int n = g.size();
    ec.assign(n, 0);
    cur.assign(n, nullptr);
    hs.assign(2 * n, {});
    H.assign(n, 0);
    int v = g.size();
    H[s] = v;
    ec[t] = 1;
    vector<int> co(2 * v);
    co[0] = v - 1;
    for (int i = 0; i < v; ++i) cur[i] = g[i].data();
    for (auto& e : g[s]) add_flow(e, e.c);
    if (hs[0].size())
      for (int hi = 0; hi >= 0;) {
        int u = hs[hi].back();
        hs[hi].pop_back();
        while (ec[u] > 0)
          if (cur[u] == g[u].data() + g[u].size()) {
            H[u] = 1e9;
            for (auto& e : g[u])
              if (e.c && H[u] > H[e.to] + 1) H[u] = H[e.to] + 1, cur[u] = &e;
            if (++co[H[u]], !--co[hi] && hi < v)
              for (int i = 0; i < v; ++i)
                if (hi < H[i] && H[i] < v) {
                  --co[H[i]];
                  H[i] = v + 1;
                }
            hi = H[u];
          } else if (cur[u]->c && H[u] == H[cur[u]->to] + 1)
            add_flow(*cur[u], min(ec[u], cur[u]->c));
          else
            ++cur[u];
        while (hi >= 0 && hs[hi].empty()) --hi;
      }
    return -ec[s];
  }
};
template <typename flow_t = long long>
struct MaxFlow {
  static constexpr flow_t INF = numeric_limits<flow_t>::max();
  PushRelabel<flow_t> flow;
  MaxFlow(const int n) : flow(n) {}
  inline void add_arc(const int u, const int v, const flow_t capacity) {
    flow.add_edge(u, v, capacity);
  }
  inline void add_edge(const int u, const int v, const flow_t capacity) {
    flow.add_edge(u, v, capacity, capacity);
  }
  inline void add_infinite_arc(const int u, const int v) {
    flow.add_edge(u, v, INF);
  }
  inline void add_infinite_edge(const int u, const int v) {
    flow.add_edge(u, v, INF, INF);
  }
  flow_t solve(const int s, const int t) { return flow.max_flow(s, t); }
};
template <typename flow_t>
class MaxFlowLR {
 private:
  static constexpr flow_t INF = numeric_limits<flow_t>::max();
  int n;
  vector<flow_t> from_source, to_sink, outgoing_capacity;
  vector<tuple<int, int, flow_t>> demands;
  flow_t total_demand;
  bool invalid;
  PushRelabel<flow_t> flow;

 public:
  MaxFlowLR(const int n)
      : n(n),
        from_source(n),
        to_sink(n),
        outgoing_capacity(n),
        total_demand(0),
        invalid(false),
        flow(n + 2) {}
  void add_arc(const int u, const int v, const flow_t demand,
               const flow_t capacity) {
    if (demand > capacity) {
      invalid = true;
      return;
    }
    if (u != v) {
      from_source[v] += demand;
      to_sink[u] += demand;
      flow.add_edge(u, v, capacity - demand);
      demands.push_back({u, v, demand});
      total_demand += demand;
      outgoing_capacity[u] += capacity;
    }
  }
  flow_t solve(const int s, const int t) {
    if (invalid) {
      return -1;
    }
    const int source = n;
    const int sink = n + 1;
    for (int v = 0; v < n; ++v) {
      if (from_source[v] != 0) {
        flow.add_edge(source, v, from_source[v]);
      }
      if (to_sink[v] != 0) {
        flow.add_edge(v, sink, to_sink[v]);
      }
    }
    flow.add_edge(t, s, INF);
    const flow_t flow_aux = flow.max_flow(source, sink);
    if (s != t) {
      flow.g[s].pop_back();
      flow.g[t].pop_back();
    }
    for (int v = n - 1; v >= 0; --v) {
      if (to_sink[v] != 0) {
        flow.g[sink].pop_back();
        flow.g[v].pop_back();
      }
      if (from_source[v] != 0) {
        flow.g[source].pop_back();
        flow.g[v].pop_back();
      }
    }
    if (flow_aux != total_demand) return -1;
    const flow_t flow_new = flow.max_flow(s, t);
    flow_t total_flow = outgoing_capacity[s];
    for (const auto& e : flow.g[s]) total_flow -= e.c;
    return total_flow;
  }
  vector<map<int, flow_t>> retrieve() {
    vector<map<int, flow_t>> ans(n);
    for (int u = 0; u < n; ++u)
      for (const auto& e : flow.g[u])
        if (e.f > 0) ans[u][e.to] += e.f, ans[e.to][u] -= e.f;
    for (auto t : demands)
      if (get<2>(t) > 0)
        ans[get<0>(t)][get<1>(t)] += get<2>(t),
            ans[get<1>(t)][get<0>(t)] -= get<2>(t);
    return ans;
  }
};
}  // namespace
inline int divceil(const int x, const int y) {
  const int q = x / y;
  return q * y == x ? q : q + 1;
}
inline long long divceil(const long long x, const long long y) {
  const long long q = x / y;
  return q * y == x ? q : q + 1;
}
map<int, int> coordinate_compression(vector<int> v) {
  sort(v.begin(), v.end());
  const int n = unique(v.begin(), v.end()) - v.begin();
  map<int, int> compr;
  for (int i = 0; i < n; ++i) compr[v[i]] = i;
  return compr;
}
map<long long, int> coordinate_compression(vector<long long> v) {
  sort(v.begin(), v.end());
  const int n = unique(v.begin(), v.end()) - v.begin();
  map<long long, int> compr;
  for (int i = 0; i < n; ++i) compr[v[i]] = i;
  return compr;
}
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  int r, b;
  scanf("%d%d", &r, &b);
  bool flip = false;
  if (r >= b) {
    flip = true;
    swap(r, b);
  }
  vector<std::pair<int, int>> original_points;
  vector<int> allx, ally;
  for (int i = 0; i < n; ++i) {
    int x, y;
    scanf("%d%d", &x, &y);
    original_points.emplace_back(x, y);
    allx.push_back(x);
    ally.push_back(y);
  }
  map<int, int> comprx = coordinate_compression(allx),
                compry = coordinate_compression(ally);
  const int xlines = comprx.rbegin()->second + 1;
  const int ylines = compry.rbegin()->second + 1;
  vector<int> xdeg(xlines), ydeg(ylines);
  vector<int> xcons(xlines), ycons(ylines);
  vector<std::pair<int, int>> points;
  for (const std::pair<int, int> p : original_points) {
    const int xx = comprx[p.first];
    const int yy = compry[p.second];
    points.emplace_back(xx, yy);
    ++xdeg[xx];
    ++ydeg[yy];
    ++xcons[xx];
    ++ycons[yy];
  }
  while (m--) {
    int t, l, d;
    scanf("%d%d%d", &t, &l, &d);
    if (t == 1) {
      const auto it = comprx.find(l);
      if (it != comprx.end()) xcons[it->second] = min(xcons[it->second], d);
    } else {
      const auto it = compry.find(l);
      if (it != compry.end()) ycons[it->second] = min(ycons[it->second], d);
    }
  }
  MaxFlowLR<long long> dinic(2 + xlines + ylines);
  const int source = 0;
  const int sink = 1;
  const auto get_xvert = [&](const int i) { return 2 + i; };
  const auto get_yvert = [&](const int i) { return 2 + xlines + i; };
  for (int i = 0; i < xlines; ++i) {
    const int L = divceil(xdeg[i] - xcons[i], 2);
    const int R = (xdeg[i] + xcons[i]) / 2;
    dinic.add_arc(source, get_xvert(i), L, R);
  }
  for (int i = 0; i < ylines; ++i) {
    const int L = divceil(ydeg[i] - ycons[i], 2);
    const int R = (ydeg[i] + ycons[i]) / 2;
    dinic.add_arc(get_yvert(i), sink, L, R);
  }
  for (const std::pair<int, int> p : points)
    dinic.add_arc(get_xvert(p.first), get_yvert(p.second), 0, 1);
  long long flow_value = dinic.solve(source, sink);
  if (flow_value == -1) {
    puts("-1");
    return 0;
  }
  long long ans = flow_value * r + (n - flow_value) * b;
  cout << ans << endl;
  map<std::pair<int, int>, int> red;
  auto flow = dinic.retrieve();
  for (int i = 0; i < xlines; ++i) {
    const int x = get_xvert(i);
    for (const auto p : flow[x]) {
      const int j = p.first - 2 - xlines;
      const int f = p.second;
      if (j >= 0) red[std::pair<int, int>(i, j)] += f;
    }
  }
  for (const std::pair<int, int> p : points) {
    int& v = red[p];
    if (v) {
      v--;
      putchar(flip ? 'b' : 'r');
    } else {
      putchar(flip ? 'r' : 'b');
    }
  }
  cout << endl;
}
