#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500005;
int n, m, q;
vector<pair<int,int>> edges;
// KRT
vector<int> adj1[MAXN * 2], adj2[MAXN * 2];
int par1[20][MAXN * 2], par2[20][MAXN * 2];
int mn1[MAXN * 2], mx1[MAXN * 2];
int mn2[MAXN * 2], mx2[MAXN * 2];
int fu1[MAXN * 2], fu2[MAXN * 2];
// Euler
int in1[MAXN * 2], out1[MAXN * 2], timer1;
int in2[MAXN * 2], out2[MAXN * 2], timer2;
// BIT
int bit[MAXN];
void upd(int i, int v) {
for (; i <= n; i += i & -i) bit[i] += v;
}
int get(int i) {
int s = 0;
for (; i > 0; i -= i & -i) s += bit[i];
return s;
}
int query(int l, int r) {
return get(r) - get(l - 1);
}
// DSU find
int find(int *fu, int x) {
return fu[x] < 0 ? x : fu[x] = find(fu, fu[x]);
}
// build KRT
int buildKRT(vector<pair<int,int>> ed, vector<int> adj[], int *fu, int *mn, int *mx) {
int tot = n;
for (int i = 1; i <= 2*n; i++) fu[i] = -1;
for (auto [u, v] : ed) {
int x = find(fu, u);
int y = find(fu, v);
if (x == y) continue;
++tot;
adj[tot].push_back(x);
adj[tot].push_back(y);
fu[x] = fu[y] = tot;
fu[tot] = -1;
}
return tot;
}
// DFS build in/out + mn/mx
void dfs1(int u) {
in1[u] = ++timer1;
if (u <= n) mn1[u] = mx1[u] = u;
else {
mn1[u] = 1e9;
mx1[u] = -1;
for (int v : adj1[u]) {
dfs1(v);
mn1[u] = min(mn1[u], mn1[v]);
mx1[u] = max(mx1[u], mx1[v]);
}
}
out1[u] = timer1;
}
void dfs2(int u) {
in2[u] = ++timer2;
if (u <= n) mn2[u] = mx2[u] = u;
else {
mn2[u] = 1e9;
mx2[u] = -1;
for (int v : adj2[u]) {
dfs2(v);
mn2[u] = min(mn2[u], mn2[v]);
mx2[u] = max(mx2[u], mx2[v]);
}
}
out2[u] = timer2;
}
// jump
int jump1(int u, int L) {
for (int k = 19; k >= 0; k--) {
int p = par1[k][u];
if (p && mn1[p] >= L) u = p;
}
return u;
}
int jump2(int u, int R) {
for (int k = 19; k >= 0; k--) {
int p = par2[k][u];
if (p && mx2[p] <= R) u = p;
}
return u;
}
struct Query {
int l1, r1, l2, r2, id, sign;
};
vector<Query> qs[MAXN];
int ans[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m >> q;
edges.resize(m);
for (auto &e : edges) cin >> e.first >> e.second;
// build KRT1 (>= L)
auto e1 = edges;
for (auto &e : e1) if (e.first > e.second) swap(e.first, e.second);
sort(e1.begin(), e1.end(), [](auto a, auto b){
return max(a.first,a.second) > max(b.first,b.second);
});
int root1 = buildKRT(e1, adj1, fu1, mn1, mx1);
// build KRT2 (<= R)
auto e2 = edges;
for (auto &e : e2) if (e.first < e.second) swap(e.first, e.second);
sort(e2.begin(), e2.end(), [](auto a, auto b){
return min(a.first,a.second) < min(b.first,b.second);
});
int root2 = buildKRT(e2, adj2, fu2, mn2, mx2);
// dfs
dfs1(root1);
dfs2(root2);
// build binary lifting
for (int i = 1; i <= root1; i++)
for (int v : adj1[i])
par1[0][v] = i;
for (int k = 1; k < 20; k++)
for (int i = 1; i <= root1; i++)
par1[k][i] = par1[k-1][par1[k-1][i]];
for (int i = 1; i <= root2; i++)
for (int v : adj2[i])
par2[0][v] = i;
for (int k = 1; k < 20; k++)
for (int i = 1; i <= root2; i++)
par2[k][i] = par2[k-1][par2[k-1][i]];
// queries
for (int i = 1; i <= q; i++) {
int S, E, L, R;
cin >> S >> E >> L >> R;
int u = jump1(S, L);
int v = jump2(E, R);
int l1 = in1[u], r1 = out1[u];
int l2 = in2[v], r2 = out2[v];
qs[r1].push_back({l1, r1, l2, r2, i, +1});
qs[l1-1].push_back({l1, r1, l2, r2, i, -1});
}
// build pos in B
vector<int> A(n+1), B(n+1), posB(n+1);
for (int i = 1; i <= n; i++) {
A[in1[i]] = i;
B[in2[i]] = i;
}
for (int i = 1; i <= n; i++) {
posB[B[i]] = i;
}
// sweep
for (int i = 1; i <= n; i++) {
int v = A[i];
int pos = posB[v];
upd(pos, 1);
for (auto qu : qs[i]) {
int val = query(qu.l2, qu.r2);
ans[qu.id] += qu.sign * val;
}
}
for (int i = 1; i <= q; i++) {
cout << (ans[i] > 0) << '\n';
}
}