#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXV = 2005;
struct DSU {
int par[MAXV], sz[MAXV];
void init(int n) {
for (int i = 0; i < n; i++) {
par[i] = i;
sz[i] = 1;
}
}
int find(int u) {
if (par[u] == u) return u;
return par[u] = find(par[u]);
}
void merge(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return;
if (sz[u] < sz[v]) swap(u, v);
par[v] = u;
sz[u] += sz[v];
}
};
struct Tree {
ll x, y, r;
};
struct Event {
ll gap;
int u, v;
bool operator < (const Event& other) const {
return gap < other.gap;
}
};
struct Query {
ll need;
int start, id;
bool operator < (const Query& other) const {
return need < other.need;
}
};
ll getGap(const Tree& a, const Tree& b) {
ll dx = a.x - b.x;
ll dy = a.y - b.y;
ll d = sqrt((long double)dx * dx + (long double)dy * dy);
return d - a.r - b.r;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
ll w, h;
cin >> n >> m >> w >> h;
vector<Tree> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i].x >> a[i].y >> a[i].r;
}
vector<Event> events;
auto addEdge = [&](int u, int v, ll gap) {
events.push_back({gap, u, v});
};
// 0 = bottom, 1 = right, 2 = top, 3 = left
// tree i has id = i + 4
for (int i = 0; i < n; i++) {
int id = i + 4;
addEdge(id, 0, a[i].y - a[i].r); // to bottom
addEdge(id, 1, w - a[i].x - a[i].r); // to right
addEdge(id, 2, h - a[i].y - a[i].r); // to top
addEdge(id, 3, a[i].x - a[i].r); // to left
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
addEdge(i + 4, j + 4, getGap(a[i], a[j]));
}
}
vector<Query> q(m);
for (int i = 0; i < m; i++) {
ll r;
int e;
cin >> r >> e;
--e;
q[i] = {2 * r, e, i};
}
sort(events.begin(), events.end());
sort(q.begin(), q.end());
static bool ok[100005][4];
memset(ok, true, sizeof(ok));
DSU dsu;
dsu.init(n + 4);
int ptr = 0;
for (const Query& cur : q) {
// allowed to touch
// so only gaps < 2r are blocked
while (ptr < (int)events.size() && events[ptr].gap < cur.need) {
dsu.merge(events[ptr].u, events[ptr].v);
ptr++;
}
bool conn[4][4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
conn[i][j] = (dsu.find(i) == dsu.find(j));
}
}
auto bad = [&](int side) {
int prev = (side == 0 ? 3 : side - 1);
return conn[prev][side];
};
bool blockHorizontal = conn[0][2];
bool blockVertical = conn[1][3];
for (int to = 0; to < 4; to++) {
if (to == cur.start) continue;
if (bad(cur.start) || bad(to)) {
ok[cur.id][to] = false;
continue;
}
if (abs(cur.start - to) == 2) {
if (blockHorizontal || blockVertical) {
ok[cur.id][to] = false;
}
} else if (cur.start + to == 3) {
if (blockVertical) {
ok[cur.id][to] = false;
}
} else {
if (blockHorizontal) {
ok[cur.id][to] = false;
}
}
}
}
for (int i = 0; i < m; i++) {
string ans = "";
for (int side = 0; side < 4; side++) {
if (ok[i][side]) ans += char('1' + side);
}
cout << ans << '\n';
}
return 0;
}