Problem:
Problem E:
Enclose Points
There are $N$ points and $M$ segments on the $xy$-plane. Each segment connects two of these
points and they don't intersect each other except at the endpoints. You are also given $Q$ points
as queries. Your task is to determine for each query point whether you can make a polygon that
encloses the query point using some of the given segments. Note that the polygon should not
necessarily be convex.
Input
Each input is formatted as follows.
$N$ $M$ $Q$
$x_1$ $y_1$
...
$x_N$ $y_N$
$a_1$ $b_1$
...
$a_M$ $b_M$
$qx_1$ $qy_1$
...
$qx_Q$ $qy_Q$
The first line contains three integers $N$ ($2 \leq N \leq 100,000$), $M$ ($1 \leq M \leq 100,000$), and $Q$
($1 \leq Q \leq 100,000$), which represent the number of points, the number of segments, and the
number of queries, respectively. Each of the following $N$ lines contains two integers $x_i$ and $y_i$
($-100,000 \leq x_i, y_i \leq 100,000$), the coordinates of the $i$-th point. The points are guaranteed to be
distinct, that is, $(x_i, y_i) \ne (x_j, y_j)$ when $i \ne j$. Each of the following $M$ lines contains two integers
$a_i$ and $b_i$ ($1 \leq a_i < b_i \leq N$), which indicate that the $i$-th segment connects the $a_i$-th point and
the $b_i$-th point. Assume that those segments do not intersect each other except at the endpoints.
Each of the following $Q$ lines contains two integers $qx_i$ and $qy_i$ ($-100,000 \leq qx_i, qy_i \leq 100,000$),
the coordinates of the $i$-th query point.
You can assume that, for any pair of query point and segment, the distance between them is at
least $10^{-4}$.
Output
The output should contain $Q$ lines. Print "Yes" on the $i$-th line if there is a polygon that
contains the $i$-th query point. Otherwise print "No" on the $i$-th line.
Sample Input
4 5 3
-10 -10
10 -10
10 10
-10 10
1 2
1 3
1 4
2 3
3 4
-20 0
1 0
20 0
Output for the Sample Input
No
Yes
No
Sample Input
8 8 5
-20 -20
20 -20
20 20
-20 20
-10 -10
10 -10
10 10
-10 10
1 2
1 4
2 3
3 4
5 6
5 8
6 7
7 8
-25 0
-15 0
0 0
15 0
25 0
Output for the Sample Input
No
Yes
Yes
Yes
No
Sample Input
8 8 5
-20 -10
-10 -10
-10 10
-20 10
10 -10
20 -10
20 10
10 10
1 2
2 3
3 4
1 4
5 6
6 7
7 8
5 8
-30 0
-15 0
0 0
15 0
30 0
Output for the Sample Input
No
Yes
No
Yes
No

Submitted solutions:

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct P {
  ll x, y;
};
P operator-(P l, P r){ return { l.x - r.x, l.y - r.y }; }
ll operator^(P l, P r){ return l.x * r.y - l.y * r.x; }
bool operator<(P l, P r){ return l.x != r.x ? l.x < r.x : l.y < r.y; }
ll sgn(ll x){ return x ? x < 0 ? -1 : 1 : 0; }

bool argcmp(P l, P r){
  if(r.y == 0 && 0 < r.x) return 0;
  if(l.y == 0 && 0 < l.x) return 1;
  ll sl = sgn(l.y), sr = sgn(r.y);
  if(sl != sr) return sl > sr;
  return (l ^ r) > 0;
}

ll dot(P a, P b) {
  return a.x * b.x + a.y * b.y;
}
ll sgncrs(P a, P b, P c){
  ll q = (b - a) ^ (c - a);
  return q ? q < 0 ? -1 : 1 : 0;
}

struct Edge {
  ll ccw;
  ll cw;
  ll from;
  ll to;
};

struct L {
  P s, t;
};
struct LI {
  L l;
  ll i;
  L reg() const { return l.s < l.t ? l : L{l.t, l.s}; }
  static ll d(P a, P b, P c){
    return c < a || b < c ? 0 : sgncrs(a, b, c);
  }
  bool operator<(LI b) const {
    L l = reg(), r = b.reg();
    if(l.t < r.s || r.t < l.s) return 0;
    ll f = 0;
    f += d(l.s, l.t, r.s) - d(r.s, r.t, l.s);
    f += d(l.s, l.t, r.t) - d(r.s, r.t, l.t);
    if(f) return 0 < f;
    if(r.s < l.t) return 0;
    if(l.s < r.t) return 1;
    return i < b.i;
  }
};
V<ll> orderSegments(V<L> e, ll inf = 1ll << 30){
  ll n = e.size(), f = 0;
  for(auto& l : e) if(l.t < l.s) swap(l.s, l.t);
  V<P> X(n*2);
  REP(i, n) X[i] = e[i].s, X[n + i] = e[i].t;
  V<ll> d(n), res(n), ord(n, -1), id(n*2);
  V<V<ll>> adj(n);
  std::set<LI> ds;
  V<std::set<LI>::iterator> its(n, ds.end());
  ds.insert({{{-inf,-inf}, {inf,-inf}}, -1});
  ds.insert({{{-inf,inf}, {inf,inf}}, -1});
  REP(i,n*2) id[i] = i;
  stable_sort(id.begin(), id.end(), [&](ll l, ll r){ return X[l] < X[r]; });
  auto addEdge = [&](ll l, ll r){
    if(l >= 0 && r >= 0) adj[l].push_back(r), d[r]++;
  };
  for(ll i : id){
    if(i < n){
      its[i] = ds.insert({e[i], i}).first;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, i), addEdge(i, (++r)->i);
    } else {
      i -= n;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, (++r)->i);
      ds.erase(its[i]);
    }
  }
  REP(i, n) if(!d[i]) ord[f++] = i;
  for(ll v : ord) if(v >= 0) for(ll w : adj[v]) if(!--d[w]) ord[f++] = w;
  REP(i, n) res[ord[i]] = i;
  return res;
}

void testcase(){
  ll N, M, Q; cin >> N >> M >> Q;
  V<P> A(N); REP(i,N) cin >> A[i].x >> A[i].y;
  V<V<ll>> adj(N);
  V<Edge> edges(M*2, {-1,-1,-1});
  auto edgeDir = [](P l, P r) -> bool {
    return l.y != r.y ? l.y < r.y : l.x < r.x;
  };
  {
    V<ll> I(N); REP(i,N) I[i] = i;
    sort(I.begin(), I.end(), [&](ll l, ll r){ return edgeDir(A[l], A[r]); });
    V<ll> O(N); REP(i,N) O[I[i]] = i;
    REP(i,M){
      ll u,v; cin >> u >> v; u--; v--; u = O[u]; v = O[v];
      adj[u].push_back(i*2);
      adj[v].push_back(i*2+1);
      edges[i*2].from = u;
      edges[i*2].to = v;
      edges[i*2+1].from = v;
      edges[i*2+1].to = u;
    }
    V<P> B(N);
    REP(i,N) B[i] = A[I[i]];
    swap(A, B);
  }
  REP(v,N) if(adj[v].size()){
    sort(adj[v].begin(), adj[v].end(), [&](ll l, ll r){
      ll f = edges[l].to, g = edges[r].to;
      return argcmp(A[f] - A[v], A[g] - A[v]);
    });
    REP(i,adj[v].size()){
      ll l = adj[v][i], r = adj[v][(i+1)%adj[v].size()];
      edges[l].ccw = r;
      edges[r].cw = l;
    }
  }

  V<ll> vis(M*2);
  V<ll> outer;
  REP(se,M*2) if(!vis[se]){
    ll area = 0;
    V<ll> echain;
    for(ll e = se; !vis[e]; e = edges[e^1].cw){
      area += A[edges[e].from] ^ A[edges[e].to];
      echain.push_back(e);
      vis[e] = 1;
    }
    if(area < 0) for(auto x : echain) outer.push_back(x);
  }

  sort(outer.begin(), outer.end());
  {
    V<ll> buf;
    for(ll x : outer){
      if(buf.size() && buf.back() == (x ^ 1)){
        buf.pop_back(); continue;
      }
      buf.push_back(x);
    }
    swap(outer, buf);
  }

  M = outer.size();

  V<P> pts(Q);
  for(auto& p : pts) cin >> p.x >> p.y;
  
  V<L> segs;
  for(auto e : outer) segs.push_back(L{ A[edges[e].from], A[edges[e].to] });
  REP(i,Q) segs.push_back(L{pts[i], pts[i]});
  auto ord = orderSegments(segs);

  struct Query {
    P pos;
    ll ty;
    ll e;
  };
  V<Query> queries;
  REP(i,Q) queries.push_back({ pts[i], 0, i });

  REP(i,M){
    ll u = edges[outer[i]].from;
    ll v = edges[outer[i]].to;
    queries.push_back({ min(A[u], A[v]), 1, i });
    queries.push_back({ max(A[u], A[v]), 2, i });
  }
  for(auto& q : queries) q.pos.y = q.pos.y * 3 + q.ty;
  sort(queries.begin(), queries.end(), [](auto& l, auto& r){ return l.pos < r.pos; });

  ll Z = M + Q;
  V<ll> fwt(Z+1);
  auto add = [&](ll p, ll v){
    p++;
    while(p <= Z){
      fwt[p] += v;
      p += p & -p;
    }
  };
  auto sum = [&](ll r){
    ll res = 0;
    while(r){
      res += fwt[r];
      r -= r & -r;
    }
    return res;
  };

  V<ll> ans(Q);
  for(auto query : queries){
    if(query.ty == 0){
      ans[query.e] = sum(ord[query.e + M]);
    }
    else {
      auto e = edges[outer[query.e]];
      bool way = A[e.from] < A[e.to];
      if(query.ty == 1){
        add(ord[query.e], way ? 1 : -1);
      }
      if(query.ty == 2){
        add(ord[query.e], way ? -1 : 1);
      }
    }
  }

  REP(i,Q) cout << (ans[i] ? "Yes\n" : "No\n");
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 66668
final_rank: 2

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct P {
  ll x, y;
};
P operator-(P l, P r){ return { l.x - r.x, l.y - r.y }; }
ll operator^(P l, P r){ return l.x * r.y - l.y * r.x; }
bool operator<(P l, P r){ return l.x != r.x ? l.x < r.x : l.y < r.y; }
ll sgn(ll x){ return x ? x < 0 ? -1 : 1 : 0; }

bool argcmp(P l, P r){
  if(r.y == 0 && 0 < r.x) return 0;
  if(l.y == 0 && 0 < l.x) return 1;
  ll sl = sgn(l.y), sr = sgn(r.y);
  if(sl != sr) return sl > sr;
  return (l ^ r) > 0;
}

ll dot(P a, P b) {
  return a.x * b.x + a.y * b.y;
}
ll sgncrs(P a, P b, P c){
  ll q = (b - a) ^ (c - a);
  return q ? q < 0 ? -1 : 1 : 0;
}

struct Edge {
  ll ccw;
  ll cw;
  ll from;
  ll to;
};

struct L {
  P s, t;
};
struct LI {
  L l;
  ll i;
  L reg() const { return l.s < l.t ? l : L{l.t, l.s}; }
  static ll d(P a, P b, P c){
    return c < a || b < c ? 0 : sgncrs(a, b, c);
  }
  bool operator<(LI b) const {
    L l = reg(), r = b.reg();
    if(l.t < r.s || r.t < l.s) return 0;
    ll f = 0;
    f += d(l.s, l.t, r.s) - d(r.s, r.t, l.s);
    f += d(l.s, l.t, r.t) - d(r.s, r.t, l.t);
    if(f) return 0 < f;
    if(r.s < l.t) return 0;
    if(l.s < r.t) return 1;
    return i < b.i;
  }
};
V<ll> orderSegments(V<L> e, ll inf = 1ll << 30){
  ll n = e.size(), f = 0;
  for(auto& l : e) if(l.t < l.s) swap(l.s, l.t);
  V<P> X(n*2);
  REP(i, n) X[i] = e[i].s, X[n + i] = e[i].t;
  V<ll> d(n), res(n), ord(n, -1), id(n*2);
  V<V<ll>> adj(n);
  std::set<LI> ds;
  V<std::set<LI>::iterator> its(n, ds.end());
  ds.insert({{{-inf,-inf}, {inf,-inf}}, -1});
  ds.insert({{{-inf,inf}, {inf,inf}}, -1});
  REP(i,n*2) id[i] = i;
  stable_sort(id.begin(), id.end(), [&](ll l, ll r){ return X[l] < X[r]; });
  auto addEdge = [&](ll l, ll r){
    if(l >= 0 && r >= 0) adj[l].push_back(r), d[r]++;
  };
  for(ll i : id){
    if(i < n){
      its[i] = ds.insert({e[i], i}).first;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, i), addEdge(i, (++r)->i);
    } else {
      i -= n;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, (++r)->i);
      ds.erase(its[i]);
    }
  }
  REP(i, n) if(!d[i]) ord[f++] = i;
  for(ll v : ord) if(v >= 0) for(ll w : adj[v]) if(!--d[w]) ord[f++] = w;
  REP(i, n) res[ord[i]] = i;
  return res;
}

void testcase(){
  ll N, M, Q; cin >> N >> M >> Q;
  V<P> A(N); REP(i,N) cin >> A[i].x >> A[i].y;
  V<V<ll>> adj(N);
  V<Edge> edges(M*2, {-1,-1,-1});
  auto edgeDir = [](P l, P r) -> bool {
    return l.y != r.y ? l.y < r.y : l.x < r.x;
  };
  {
    V<ll> I(N); REP(i,N) I[i] = i;
    sort(I.begin(), I.end(), [&](ll l, ll r){ return edgeDir(A[l], A[r]); });
    V<ll> O(N); REP(i,N) O[I[i]] = i;
    REP(i,M){
      ll u,v; cin >> u >> v; u--; v--; u = O[u]; v = O[v];
      adj[u].push_back(i*2);
      adj[v].push_back(i*2+1);
      edges[i*2].from = u;
      edges[i*2].to = v;
      edges[i*2+1].from = v;
      edges[i*2+1].to = u;
    }
    V<P> B(N);
    REP(i,N) B[i] = A[I[i]];
    swap(A, B);
  }
  REP(v,N) if(adj[v].size()){
    sort(adj[v].begin(), adj[v].end(), [&](ll l, ll r){
      ll f = edges[l].to, g = edges[r].to;
      return argcmp(A[f] - A[v], A[g] - A[v]);
    });
    REP(i,adj[v].size()){
      ll l = adj[v][i], r = adj[v][(i+1)%adj[v].size()];
      edges[l].ccw = r;
      edges[r].cw = l;
    }
  }

  V<ll> vis(M*2);
  V<ll> outer;
  REP(se,M*2) if(!vis[se]){
    ll area = 0;
    V<ll> echain;
    for(ll e = se; !vis[e]; e = edges[e^1].cw){
      area += A[edges[e].from] ^ A[edges[e].to];
      echain.push_back(e);
      vis[e] = 1;
    }
    if(area < 0) for(auto x : echain) outer.push_back(x);
  }

  sort(outer.begin(), outer.end());
  {
    V<ll> buf;
    for(ll x : outer){
      if(buf.size() && buf.back() == (x ^ 1)){
        buf.pop_back(); continue;
      }
      buf.push_back(x);
    }
    swap(outer, buf);
  }

  M = outer.size();

  V<P> pts(Q);
  for(auto& p : pts) cin >> p.x >> p.y;
  
  V<L> segs;
  for(auto e : outer) segs.push_back(L{ A[edges[e].from], A[edges[e].to] });
  REP(i,Q) segs.push_back(L{pts[i], pts[i]});
  auto ord = orderSegments(segs);

  struct Query {
    P pos;
    ll ty;
    ll e;
  };
  V<Query> queries;
  REP(i,Q) queries.push_back({ pts[i], 0, i });

  REP(i,M){
    ll u = edges[outer[i]].from;
    ll v = edges[outer[i]].to;
    queries.push_back({ min(A[u], A[v]), 1, i });
    queries.push_back({ max(A[u], A[v]), 2, i });
  }
  for(auto& q : queries) q.pos.y = q.pos.y * 3 + q.ty;
  sort(queries.begin(), queries.end(), [](auto& l, auto& r){ return l.pos < r.pos; });

  ll Z = M + Q;
  V<ll> fwt(Z+1);
  auto add = [&](ll p, ll v){
    p++;
    while(p <= Z){
      fwt[p] += v;
      p += p & -p;
    }
  };
  auto sum = [&](ll r){
    ll res = 0;
    while(r){
      res += fwt[r];
      r -= r & -r;
    }
    return res;
  };

  V<ll> ans(Q);
  for(auto query : queries){
    if(query.ty == 0){
      ans[query.e] = sum(ord[query.e + M]);
    }
    else {
      auto e = edges[outer[query.e]];
      bool way = A[e.from] < A[e.to];
      if(query.ty == 1){
        add(ord[query.e], way ? 1 : -1);
      }
      if(query.ty == 2){
        add(ord[query.e], way ? -1 : 1);
      }
    }
  }

  REP(i,Q) cout << (ans[i] ? "Yes\n" : "No\n");
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 67480
final_rank: 3

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct P {
  ll x, y;
};
P operator-(P l, P r){ return { l.x - r.x, l.y - r.y }; }
ll operator^(P l, P r){ return l.x * r.y - l.y * r.x; }
bool operator<(P l, P r){ return l.x != r.x ? l.x < r.x : l.y < r.y; }
ll sgn(ll x){ return x ? x < 0 ? -1 : 1 : 0; }

bool argcmp(P l, P r){
  if(r.y == 0 && 0 < r.x) return 0;
  if(l.y == 0 && 0 < l.x) return 1;
  ll sl = sgn(l.y), sr = sgn(r.y);
  if(sl != sr) return sl > sr;
  return (l ^ r) > 0;
}

ll dot(P a, P b) {
  return a.x * b.x + a.y * b.y;
}
ll sgncrs(P a, P b, P c){
  ll q = (b - a) ^ (c - a);
  return q ? q < 0 ? -1 : 1 : 0;
}

struct Edge {
  ll ccw;
  ll cw;
  ll from;
  ll to;
};

struct L {
  P s, t;
};
struct LI {
  L l;
  ll i;
  L reg() const { return l.s < l.t ? l : L{l.t, l.s}; }
  static ll d(P a, P b, P c){
    return c < a || b < c ? 0 : sgncrs(a, b, c);
  }
  bool operator<(LI b) const {
    L l = reg(), r = b.reg();
    if(l.t < r.s || r.t < l.s) return 0;
    ll f = 0;
    f += d(l.s, l.t, r.s) - d(r.s, r.t, l.s);
    f += d(l.s, l.t, r.t) - d(r.s, r.t, l.t);
    if(f) return 0 < f;
    if(r.s < l.t) return 0;
    if(l.s < r.t) return 1;
    return i < b.i;
  }
};
V<ll> orderSegments(V<L> e, ll inf = 1ll << 30){
  ll n = e.size(), f = 0;
  for(auto& l : e) if(l.t < l.s) swap(l.s, l.t);
  V<P> X(n*2);
  REP(i, n) X[i] = e[i].s, X[n + i] = e[i].t;
  V<ll> d(n), res(n), ord(n, -1), id(n*2);
  V<V<ll>> adj(n);
  std::set<LI> ds;
  V<std::set<LI>::iterator> its(n, ds.end());
  ds.insert({{{-inf,-inf}, {inf,-inf}}, -1});
  ds.insert({{{-inf,inf}, {inf,inf}}, -1});
  REP(i,n*2) id[i] = i;
  stable_sort(id.begin(), id.end(), [&](ll l, ll r){ return X[l] < X[r]; });
  auto addEdge = [&](ll l, ll r){
    if(l >= 0 && r >= 0) adj[l].push_back(r), d[r]++;
  };
  for(ll i : id){
    if(i < n){
      its[i] = ds.insert({e[i], i}).first;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, i), addEdge(i, (++r)->i);
    } else {
      i -= n;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, (++r)->i);
      ds.erase(its[i]);
    }
  }
  REP(i, n) if(!d[i]) ord[f++] = i;
  for(ll v : ord) if(v >= 0) for(ll w : adj[v]) if(!--d[w]) ord[f++] = w;
  REP(i, n) res[ord[i]] = i;
  return res;
}

void testcase(){
  ll N, M, Q; cin >> N >> M >> Q;
  V<P> A(N); REP(i,N) cin >> A[i].x >> A[i].y;
  V<V<ll>> adj(N);
  V<Edge> edges(M*2, {-1,-1,-1});
  auto edgeDir = [](P l, P r) -> bool {
    return l.y != r.y ? l.y < r.y : l.x < r.x;
  };
  {
    V<ll> I(N); REP(i,N) I[i] = i;
    sort(I.begin(), I.end(), [&](ll l, ll r){ return edgeDir(A[l], A[r]); });
    V<ll> O(N); REP(i,N) O[I[i]] = i;
    REP(i,M){
      ll u,v; cin >> u >> v; u--; v--; u = O[u]; v = O[v];
      adj[u].push_back(i*2);
      adj[v].push_back(i*2+1);
      edges[i*2].from = u;
      edges[i*2].to = v;
      edges[i*2+1].from = v;
      edges[i*2+1].to = u;
    }
    V<P> B(N);
    REP(i,N) B[i] = A[I[i]];
    swap(A, B);
  }
  REP(v,N) if(adj[v].size()){
    sort(adj[v].begin(), adj[v].end(), [&](ll l, ll r){
      ll f = edges[l].to, g = edges[r].to;
      return argcmp(A[f] - A[v], A[g] - A[v]);
    });
    REP(i,adj[v].size()){
      ll l = adj[v][i], r = adj[v][(i+1)%adj[v].size()];
      edges[l].ccw = r;
      edges[r].cw = l;
    }
  }

  V<ll> vis(M*2);
  V<ll> outer;
  REP(se,M*2) if(!vis[se]){
    ll area = 0;
    V<ll> echain;
    for(ll e = se; !vis[e]; e = edges[e^1].cw){
      area += A[edges[e].from] ^ A[edges[e].to];
      echain.push_back(e);
      vis[e] = 1;
    }
    if(area < 0) for(auto x : echain) outer.push_back(x);
  }

  sort(outer.begin(), outer.end());
  {
    V<ll> buf;
    for(ll x : outer){
      if(buf.size() && buf.back() == (x ^ 1)){
        buf.pop_back(); continue;
      }
      buf.push_back(x);
    }
    swap(outer, buf);
  }

  M = outer.size();

  V<P> pts(Q);
  for(auto& p : pts) cin >> p.x >> p.y;
  
  //for(auto p : A){
  //  cout << "point(" << p.x << "," << p.y << ");\n";
  //}
  //for(auto ei : outer){
  //  auto e = edges[ei];
  //  cout << "line(" << e.from << "," << e.to << ");\n";
  //} cout << endl;
  
  V<L> segs;
  for(auto e : outer) segs.push_back(L{ A[edges[e].from], A[edges[e].to] });
  REP(i,Q) segs.push_back(L{pts[i], pts[i]});
  auto ord = orderSegments(segs);

  struct Query {
    P pos;
    ll ty;
    ll e;
  };
  V<Query> queries;
  REP(i,Q) queries.push_back({ pts[i], 0, i });

  REP(i,M){
    ll u = edges[outer[i]].from;
    ll v = edges[outer[i]].to;
    queries.push_back({ min(A[u], A[v]), 1, i });
    queries.push_back({ max(A[u], A[v]), 2, i });
  }
  for(auto& q : queries) q.pos.x = q.pos.x * 3 + q.ty;
  sort(queries.begin(), queries.end(), [](auto& l, auto& r){ return l.pos < r.pos; });

  ll Z = M + Q;
  V<ll> fwt(Z+1);
  auto add = [&](ll p, ll v){
    p++;
    while(p <= Z){
      fwt[p] += v;
      p += p & -p;
    }
  };
  auto sum = [&](ll r){
    ll res = 0;
    while(r){
      res += fwt[r];
      r -= r & -r;
    }
    return res;
  };

  V<ll> ans(Q);
  for(auto query : queries){
    if(query.ty == 0){
      ans[query.e] = sum(ord[query.e + M]);
    }
    else {
      auto e = edges[outer[query.e]];
      bool way = A[e.from] < A[e.to];
      if(query.ty == 1){
        add(ord[query.e], way ? 1 : -1);
      }
      if(query.ty == 2){
        add(ord[query.e], way ? -1 : 1);
      }
    }
  }

  REP(i,Q) cout << (ans[i] ? "Yes\n" : "No\n");
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 0.3793103448275862
time_ms: 30
memory_kb: 16996
final_rank: 15

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct P {
  ll x, y;
};
P operator-(P l, P r){ return { l.x - r.x, l.y - r.y }; }
ll operator^(P l, P r){ return l.x * r.y - l.y * r.x; }
bool operator<(P l, P r){ return l.x != r.x ? l.x < r.x : l.y < r.y; }
ll sgn(ll x){ return x ? x < 0 ? -1 : 1 : 0; }

bool argcmp(P l, P r){
  if(r.y == 0 && 0 < r.x) return 0;
  if(l.y == 0 && 0 < l.x) return 1;
  ll sl = sgn(l.y), sr = sgn(r.y);
  if(sl != sr) return sl > sr;
  return (l ^ r) > 0;
}

ll dot(P a, P b) {
  return a.x * b.x + a.y * b.y;
}
ll sgncrs(P a, P b, P c){
  ll q = (b - a) ^ (c - a);
  return q ? q < 0 ? -1 : 1 : 0;
}

struct Edge {
  ll ccw;
  ll cw;
  ll from;
  ll to;
};

struct L {
  P s, t;
};
struct LI {
  L l;
  ll i;
  L reg() const { return l.s < l.t ? l : L{l.t, l.s}; }
  static ll d(P a, P b, P c){
    return c < a || b < c ? 0 : sgncrs(a, b, c);
  }
  bool operator<(LI b) const {
    L l = reg(), r = b.reg();
    if(l.t < r.s || r.t < l.s) return 0;
    ll f = 0;
    f += d(l.s, l.t, r.s) - d(r.s, r.t, l.s);
    f += d(l.s, l.t, r.t) - d(r.s, r.t, l.t);
    if(f) return 0 < f;
    if(r.s < l.t) return 0;
    if(l.s < r.t) return 1;
    return i < b.i;
  }
};
V<ll> orderSegments(V<L> e, ll inf = 1ll << 30){
  ll n = e.size(), f = 0;
  V<P> X(n*2);
  REP(i, n) X[i * 2] = e[i].s, X[i * 2 + 1] = e[i].t;
  V<ll> d(n), res(n), ord(n), vis(n), id(n*2);
  V<V<ll>> adj(n);
  std::set<LI> ds;
  V<std::set<LI>::iterator> its(n, ds.end());
  ds.insert({{{-inf,-inf}, {inf,-inf}}, -1});
  ds.insert({{{-inf,inf}, {inf,inf}}, -1});
  REP(i,n*2) id[i] = i;
  sort(id.begin(), id.end(), [&](ll l, ll r){ return X[l] < X[r]; });
  auto addEdge = [&](ll l, ll r){
    if(l >= 0 && r >= 0) adj[l].push_back(r), d[r]++;
  };
  for(ll i : id){
    if(vis[i /= 2]){
      auto l = its[i], r = its[i];
      addEdge((--l)->i, (++r)->i);
      ds.erase(its[i]);
    } else {
      its[i] = ds.insert({e[i], i}).first;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, i), addEdge(i, (++r)->i);
    }
    vis[i] ^= 1;
  }
  REP(i, n) if(!d[i]) ord[f++] = i;
  for(ll v : ord) for(ll w : adj[v]) if(!--d[w]) ord[f++] = w;
  REP(i, n) res[ord[i]] = i;
  return res;
}

void testcase(){
  ll N, M, Q; cin >> N >> M >> Q;
  V<P> A(N); REP(i,N) cin >> A[i].x >> A[i].y;
  V<V<ll>> adj(N);
  V<Edge> edges(M*2, {-1,-1,-1});
  auto edgeDir = [](P l, P r) -> bool {
    return l.y != r.y ? l.y < r.y : l.x < r.x;
  };
  {
    V<ll> I(N); REP(i,N) I[i] = i;
    sort(I.begin(), I.end(), [&](ll l, ll r){ return edgeDir(A[l], A[r]); });
    V<ll> O(N); REP(i,N) O[I[i]] = i;
    REP(i,M){
      ll u,v; cin >> u >> v; u--; v--; u = O[u]; v = O[v];
      adj[u].push_back(i*2);
      adj[v].push_back(i*2+1);
      edges[i*2].from = u;
      edges[i*2].to = v;
      edges[i*2+1].from = v;
      edges[i*2+1].to = u;
    }
    V<P> B(N);
    REP(i,N) B[i] = A[I[i]];
    swap(A, B);
  }
  REP(v,N) if(adj[v].size()){
    sort(adj[v].begin(), adj[v].end(), [&](ll l, ll r){
      ll f = edges[l].to, g = edges[r].to;
      return argcmp(A[f] - A[v], A[g] - A[v]);
    });
    REP(i,adj[v].size()){
      ll l = adj[v][i], r = adj[v][(i+1)%adj[v].size()];
      edges[l].ccw = r;
      edges[r].cw = l;
    }
  }

  V<ll> vis(M*2);
  V<ll> outer;
  REP(se,M*2) if(!vis[se]){
    ll area = 0;
    V<ll> echain;
    for(ll e = se; !vis[e]; e = edges[e^1].cw){
      area += A[edges[e].from] ^ A[edges[e].to];
      echain.push_back(e);
      vis[e] = 1;
    }
    if(area < 0) for(auto x : echain) outer.push_back(x);
  }

  sort(outer.begin(), outer.end());
  {
    V<ll> buf;
    for(ll x : outer){
      if(buf.size() && buf.back() == (x ^ 1)){
        buf.pop_back(); continue;
      }
      buf.push_back(x);
    }
    swap(outer, buf);
  }

  M = outer.size();

  V<P> pts(Q);
  for(auto& p : pts) cin >> p.x >> p.y;
  
  //for(auto p : A){
  //  cout << "point(" << p.x << "," << p.y << ");\n";
  //}
  //for(auto ei : outer){
  //  auto e = edges[ei];
  //  cout << "line(" << e.from << "," << e.to << ");\n";
  //} cout << endl;
  
  V<L> segs;
  for(auto e : outer) segs.push_back(L{ A[edges[e].from], A[edges[e].to] });
  REP(i,Q) segs.push_back(L{pts[i], pts[i]});
  auto ord = orderSegments(segs);

  struct Query {
    P pos;
    ll ty;
    ll e;
  };
  V<Query> queries;
  REP(i,Q) queries.push_back({ pts[i], 0, i });

  REP(i,M){
    ll u = edges[outer[i]].from;
    ll v = edges[outer[i]].to;
    queries.push_back({ min(A[u], A[v]), 1, i });
    queries.push_back({ max(A[u], A[v]), 2, i });
  }
  for(auto& q : queries) q.pos.x = q.pos.x * 3 + q.ty;
  sort(queries.begin(), queries.end(), [](auto& l, auto& r){ return l.pos < r.pos; });

  ll Z = M + Q;
  V<ll> fwt(Z+1);
  auto add = [&](ll p, ll v){
    p++;
    while(p <= Z){
      fwt[p] += v;
      p += p & -p;
    }
  };
  auto sum = [&](ll r){
    ll res = 0;
    while(r){
      res += fwt[r];
      r -= r & -r;
    }
    return res;
  };

  V<ll> ans(Q);
  for(auto query : queries){
    if(query.ty == 0){
      ans[query.e] = sum(ord[query.e + M]);
    }
    else {
      auto e = edges[outer[query.e]];
      bool way = A[e.from] < A[e.to];
      if(query.ty == 1){
        add(ord[query.e], way ? 1 : -1);
      }
      if(query.ty == 2){
        add(ord[query.e], way ? -1 : 1);
      }
    }
  }

  REP(i,Q) cout << (ans[i] ? "Yes\n" : "No\n");
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 0.3793103448275862
time_ms: 30
memory_kb: 17384
final_rank: 16

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct P {
  ll x, y;
};
P operator-(P l, P r){ return { l.x - r.x, l.y - r.y }; }
ll operator^(P l, P r){ return l.x * r.y - l.y * r.x; }
bool operator<(P l, P r){ return l.x != r.x ? l.x < r.x : l.y < r.y; }
ll sgn(ll x){ return x ? x < 0 ? -1 : 1 : 0; }

bool argcmp(P l, P r){
  if(r.y == 0 && 0 < r.x) return 0;
  if(l.y == 0 && 0 < l.x) return 1;
  ll sl = sgn(l.y), sr = sgn(r.y);
  if(sl != sr) return sl > sr;
  return (l ^ r) > 0;
}

ll dot(P a, P b) {
  return a.x * b.x + a.y * b.y;
}
ll sgncrs(P a, P b, P c){
  ll q = (b - a) ^ (c - a);
  return q ? q < 0 ? -1 : 1 : 0;
}

struct Edge {
  ll ccw;
  ll cw;
  ll from;
  ll to;
};

struct L {
  P s, t;
};
struct LI {
  L l;
  ll i;
  L reg() const { return l.s < l.t ? l : L{l.t, l.s}; }
  static ll d(P a, P b, P c){
    if(c.x < a.x || b.x < c.x) return 0;
    if(sgncrs(a, b, c)) return sgncrs(a, b, c);
    if(!dot(b - a, c - a)) return 0;
    return sgn(dot(b - a, c - a));
  }
  bool operator<(LI b) const {
    L l = reg(), r = b.reg();
    ll f = 0;
    f += d(l.s, l.t, r.s) - d(r.s, r.t, l.s);
    f += d(l.s, l.t, r.t) - d(r.s, r.t, l.t);
    return f ? 0 < f : i < b.i;
  }
};
V<ll> orderSegments(V<L> e, ll inf = 1ll << 30){
  ll n = e.size(), f = 0;
  V<P> X(n*2);
  REP(i, n) X[i * 2] = e[i].s, X[i * 2 + 1] = e[i].t;
  V<ll> d(n), res(n), ord(n), vis(n), id(n*2);
  V<V<ll>> adj(n);
  std::set<LI> ds;
  V<std::set<LI>::iterator> its(n, ds.end());
  ds.insert({{{-inf,-inf}, {inf,-inf}}, -1});
  ds.insert({{{-inf,inf}, {inf,inf}}, -1});
  REP(i,n*2) id[i] = i;
  sort(id.begin(), id.end(), [&](ll l, ll r){ return X[l] < X[r]; });
  auto addEdge = [&](ll l, ll r){
    if(l >= 0 && r >= 0) adj[l].push_back(r), d[r]++;
  };
  for(ll i : id){
    if(vis[i /= 2]){
      auto l = its[i], r = its[i];
      addEdge((--l)->i, (++r)->i);
      ds.erase(its[i]);
    } else {
      its[i] = ds.insert({e[i], i}).first;
      auto l = its[i], r = its[i];
      addEdge((--l)->i, i), addEdge(i, (++r)->i);
    }
    vis[i] ^= 1;
  }
  REP(i, n) if(!d[i]) ord[f++] = i;
  for(ll v : ord) for(ll w : adj[v]) if(!--d[w]) ord[f++] = w;
  REP(i, n) res[ord[i]] = i;
  return res;
}

void testcase(){
  ll N, M, Q; cin >> N >> M >> Q;
  V<P> A(N); REP(i,N) cin >> A[i].x >> A[i].y;
  V<V<ll>> adj(N);
  V<Edge> edges(M*2, {-1,-1,-1});
  auto edgeDir = [](P l, P r) -> bool {
    return l.y != r.y ? l.y < r.y : l.x < r.x;
  };
  {
    V<ll> I(N); REP(i,N) I[i] = i;
    sort(I.begin(), I.end(), [&](ll l, ll r){ return edgeDir(A[l], A[r]); });
    V<ll> O(N); REP(i,N) O[I[i]] = i;
    REP(i,M){
      ll u,v; cin >> u >> v; u--; v--; u = O[u]; v = O[v];
      adj[u].push_back(i*2);
      adj[v].push_back(i*2+1);
      edges[i*2].from = u;
      edges[i*2].to = v;
      edges[i*2+1].from = v;
      edges[i*2+1].to = u;
    }
    V<P> B(N);
    REP(i,N) B[i] = A[I[i]];
    swap(A, B);
  }
  REP(v,N) if(adj[v].size()){
    sort(adj[v].begin(), adj[v].end(), [&](ll l, ll r){
      ll f = edges[l].to, g = edges[r].to;
      return argcmp(A[f] - A[v], A[g] - A[v]);
    });
    REP(i,adj[v].size()){
      ll l = adj[v][i], r = adj[v][(i+1)%adj[v].size()];
      edges[l].ccw = r;
      edges[r].cw = l;
    }
  }

  V<ll> vis(M*2);
  V<ll> outer;
  REP(se,M*2) if(!vis[se]){
    ll area = 0;
    V<ll> echain;
    for(ll e = se; !vis[e]; e = edges[e^1].cw){
      area += A[edges[e].from] ^ A[edges[e].to];
      echain.push_back(e);
      vis[e] = 1;
    }
    if(area < 0) for(auto x : echain) outer.push_back(x);
  }

  sort(outer.begin(), outer.end());
  {
    V<ll> buf;
    for(ll x : outer){
      if(buf.size() && buf.back() == (x ^ 1)){
        buf.pop_back(); continue;
      }
      buf.push_back(x);
    }
    swap(outer, buf);
  }

  M = outer.size();

  V<P> pts(Q);
  for(auto& p : pts) cin >> p.x >> p.y;
  
  //for(auto p : A){
  //  cout << "point(" << p.x << "," << p.y << ");\n";
  //}
  //for(auto ei : outer){
  //  auto e = edges[ei];
  //  cout << "line(" << e.from << "," << e.to << ");\n";
  //} cout << endl;
  
  V<L> segs;
  for(auto e : outer) segs.push_back(L{ A[edges[e].from], A[edges[e].to] });
  REP(i,Q) segs.push_back(L{pts[i], pts[i]});
  auto ord = orderSegments(segs);

  struct Query {
    P pos;
    ll ty;
    ll e;
  };
  V<Query> queries;
  REP(i,Q) queries.push_back({ pts[i], 0, i });

  REP(i,M){
    ll u = edges[outer[i]].from;
    ll v = edges[outer[i]].to;
    queries.push_back({ min(A[u], A[v]), 1, i });
    queries.push_back({ max(A[u], A[v]), 2, i });
  }
  for(auto& q : queries) q.pos.x = q.pos.x * 3 + q.ty;
  sort(queries.begin(), queries.end(), [](auto& l, auto& r){ return l.pos < r.pos; });

  ll Z = M + Q;
  V<ll> fwt(Z+1);
  auto add = [&](ll p, ll v){
    p++;
    while(p <= Z){
      fwt[p] += v;
      p += p & -p;
    }
  };
  auto sum = [&](ll r){
    ll res = 0;
    while(r){
      res += fwt[r];
      r -= r & -r;
    }
    return res;
  };

  V<ll> ans(Q);
  for(auto query : queries){
    if(query.ty == 0){
      ans[query.e] = sum(ord[query.e + M]);
    }
    else {
      auto e = edges[outer[query.e]];
      bool way = A[e.from] < A[e.to];
      if(query.ty == 1){
        add(ord[query.e], way ? 1 : -1);
      }
      if(query.ty == 2){
        add(ord[query.e], way ? -1 : 1);
      }
    }
  }

  REP(i,Q) cout << (ans[i] ? "Yes\n" : "No\n");
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 0.3793103448275862
time_ms: 20
memory_kb: 17384
final_rank: 14

code_snippet: // AOJ #2721 Enclose Points
// 2025.3.25

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {
	int n = 0; int c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Couts(const string &s) {
    for (char c : s) pc(c);
    pc('\n');
}

const int NMAX = 101000;
int n, m;

struct Point {
    ll x, y;
    Point operator-(const Point &p) const {
        return { x - p.x, y - p.y };
    }
    bool isPos() const {
        return (x > 0) || (x == 0 && y > 0);
    }
};

Point w[NMAX], QP[NMAX];

struct Ord {
    Point vec;
    int id;
    bool operator<(const Ord &o) const {
        if (vec.isPos() != o.vec.isPos()) return vec.isPos();
        return vec.y * o.vec.x < o.vec.y * vec.x;
    }
};

struct Edge { int u, v; };
Edge ed[2 * NMAX];
vector<int> F[NMAX];
ll curX;

struct Frac {
    ll A, B;
    Frac() {}
    Frac(ll a, ll b) : A(a), B(b) {}
    bool operator<(const Frac &f) const {
        if ((A < 0) != (f.A < 0)) return A < 0;
        if (A < 0) return Frac(-f.A, f.B) < Frac(-A, B);
        if (A / B != f.A / f.B) return A / B < f.A / f.B;
        ll r1 = A % B, r2 = f.A % f.B;
        return r1 * f.B < r2 * B;
    }
};

struct Seg {
    Point s, t;
    int id;
    Frac curY() const {
        return { s.y * (t.x - s.x) + (curX - s.x) * (t.y - s.y), t.x - s.x };
    }
    bool operator<(const Seg &o) const {
        Frac y1 = curY(), y2 = o.curY();
        if (y1 < y2) return true;
        if (y2 < y1) return false;
        bool cmp = (t.y - s.y) * (o.t.x - o.s.x) > (o.t.y - o.s.y) * (t.x - s.x);
        if (s.x == curX) return !cmp;
        return cmp;
    }
};

set<Seg> segSet;
int num[2 * NMAX];
int visEdge[2 * NMAX];
int compCnt;
int XC, Q;
int outer[2 * NMAX];
int ansArr[NMAX];
ll X[2 * NMAX];

vector<int> inEdges[2 * NMAX], outEdges[2 * NMAX];
vector<int> putIdx[2 * NMAX];

void traverseEdge(int a) {
    if (visEdge[a]) return;
    visEdge[a] = compCnt;
    int vtx = ed[a].v;
    int idx = (num[a ^ 1] + 1) % F[vtx].size();
    traverseEdge(F[vtx][idx]);
}

int getXIdx(ll x) {
    return lower_bound(X + 1, X + XC + 1, x) - X;
}

int getVal(Point qp) {
    if (segSet.empty()) return 0;
    Point b = { qp.x - 1, qp.y };
    auto it = segSet.lower_bound({ b, qp, 0 });
    if (it == segSet.end()) return 0;
    return !outer[visEdge[it->id]];
}

int comp[NMAX];
int compId;
vector<int> graph[NMAX];
vector<int> tp;

void dfs(int a) {
    tp.push_back(a);
    comp[a] = compId;
    for (int nx : graph[a]) if (!comp[nx]) dfs(nx);
}

int compMark[NMAX], mark[NMAX];

void addSeg(Seg s) {
    int i = s.id;
    int cid = comp[ed[i].u];
    if (mark[cid] == 2) return;
    if (!mark[cid]) {
        mark[cid] = 1;
        auto it = segSet.lower_bound(s);
        if (it != segSet.end() && !outer[visEdge[it->id]]) {
            mark[cid] = 2;
            return;
        }
    }
    segSet.insert(s);
}

void delSeg(int a) {
    Seg key = { w[ed[a].u], w[ed[a].v], a };
    auto it = segSet.find(key);
    if (it == segSet.end() || it->id != a) return;
    segSet.erase(it);
}

int main(){
    int i, j;
    n = Cin(), m = Cin(), Q = Cin();
    XC = 0;
    for (i = 1; i <= n; i++){
        int x = Cin(), y = Cin();
        w[i] = {x, y};
        X[++XC] = w[i].x;
    }
    for (i = 0; i < m; i++){
        int a = Cin(), b = Cin();
        graph[a].push_back(b);
        graph[b].push_back(a);
        ed[i * 2] = {a, b};
        F[a].push_back(i * 2);
        ed[i * 2 + 1] = {b, a};
        F[b].push_back(i * 2 + 1);
    }
    for (i = 1; i <= n; i++){
        if (F[i].empty()) continue;
        vector<Ord> ord;
        for (j = 0; j < (int)F[i].size(); j++){
            int id = F[i][j];
            ord.push_back({ w[ed[id].v] - w[i], id });
        }
        sort(ord.begin(), ord.end());
        F[i].clear();
        for (j = 0; j < (int)ord.size(); j++){
            num[ord[j].id] = F[i].size();
            F[i].push_back(ord[j].id);
        }
    }
    compCnt = 0;
    for (i = 0; i < 2 * m; i++){
        if (!visEdge[i]){
            compCnt++;
            traverseEdge(i);
        }
    }
    for (i = 1; i <= n; i++){
        if (!comp[i]){
            tp.clear();
            compId++;
            dfs(i);
            int mn = tp[0];
            for (j = 1; j < (int)tp.size(); j++)
                if ((w[mn] - w[tp[j]]).isPos()) mn = tp[j];
            if (!F[mn].empty()) outer[visEdge[F[mn][0]]]=1;
        }
    }
    for (i = 1; i <= Q; i++){
        int x = Cin(), y = Cin();
        QP[i] = {x, y};
        X[++XC] = QP[i].x;
    }
    sort(X + 1, X + XC + 1);
    for (i = 0; i < 2 * m; i++){
        Point p1 = w[ed[i].u], p2 = w[ed[i].v];
        if (p1.x < p2.x) {
            inEdges[getXIdx(p1.x)].push_back(i);
            outEdges[getXIdx(p2.x)].push_back(i);
        }
    }
    for (i = 1; i <= Q; i++) putIdx[getXIdx(QP[i].x)].push_back(i);
    for (i = 1; i <= XC; i++){
        curX = X[i];
        for (j = 0; j < (int)putIdx[i].size(); j++){
            int idx = putIdx[i][j];
            ansArr[idx] = getVal(QP[idx]);
        }
        for (j = 0; j < (int)outEdges[i].size(); j++)
            delSeg(outEdges[i][j]);

        vector<Seg> segs;
        for (int id : inEdges[i])
            segs.push_back({ w[ed[id].u], w[ed[id].v], id });
        if (segs.empty()) continue;
        sort(segs.begin(), segs.end());
        for (j = segs.size() - 1; j >= 0; j--) addSeg(segs[j]);
    }
    for (i = 1; i <= Q; i++) Couts(ansArr[i] ? "Yes" : "No");
    return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 55360
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005
#define MAX 3

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct DATA{
	DATA(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	DATA(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct DATA& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(isL != arg.isL){

			if(isL){ //■削除命令を先に処理する

				return false;
			}else{

				return true;
			}

		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct SegInfo{
	SegInfo(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	SegInfo(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct SegInfo &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct SegInfo &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_DATAENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_DATAENT;
}

//傾きを求める関数
double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}

	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue; //■時計回りでないならSKIP
				tmp_S *= -1;

				poly_S[V.size()] = tmp_S;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
			}
		}
	}

	vector<DATA> vec_data;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				continue; //■1つの辺が複数回使われる場合は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			double tmp_section = calc_section(Line(point[from],point[to]));

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			vec_data.push_back(DATA(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_data.push_back(DATA(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}

	for(int i = 0; i < numQ; i++){

		vec_data.push_back(DATA(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_data.begin(),vec_data.end());

	set<SegInfo> posSET;

	for(int i = 0; i < vec_data.size(); i++){

		DATA data = vec_data[i];

		baseX = data.x; //■sort用のxを更新

		if(data.isQuery){

			if(posSET.size() == 0){

				continue;
			}
			auto at = posSET.lower_bound({0,data.y-EPS,0,0});
			if(at != posSET.begin()){


				at--;
				if(TO_R[at->ind]){

					ANS[data.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[data.poly_ind]){

				if(!data.isL){

					auto at = posSET.lower_bound({SLOPE[data.ind],SEC[data.ind]-2*EPS,(int)data.isToR,data.ind});

					//■誤差対策
					for(int k = 0; k < MAX; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == data.ind){
							posSET.erase(at);
							break;
						}
						at++;
					}
				}

				continue;
			}

			if(COUNT[data.poly_ind] == 0){ //最も左の点
				COUNT[data.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる

				if(posSET.size() > 0){

					auto at = posSET.lower_bound({0,data.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;

						if(TO_R[at->ind]){

							POL_DEL[data.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(data.isL){

				posSET.insert({SLOPE[data.ind],SEC[data.ind],(int)data.isToR,data.ind});

			}else{  //右の点

				auto at = posSET.lower_bound({SLOPE[data.ind],SEC[data.ind]-2*EPS,(int)data.isToR,data.ind});


				//■誤差対策
				for(int k = 0; k < MAX; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == data.ind){
						posSET.erase(at);
						break;
					}
					at++;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 1
time_ms: 3600
memory_kb: 180520
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005
#define MAX 3

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct DATA{
	DATA(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	DATA(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct DATA& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(isL != arg.isL){

			if(isL){ //■削除命令を先に処理する

				return false;
			}else{

				return true;
			}

		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct SegInfo{
	SegInfo(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	SegInfo(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct SegInfo &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct SegInfo &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_DATAENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_DATAENT;
}

//傾きを求める関数
double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}

	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue; //■時計回りでないならSKIP
				tmp_S *= -1;

				poly_S[V.size()] = tmp_S;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
			}
		}
	}

	vector<DATA> vec_data;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			vec_data.push_back(DATA(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_data.push_back(DATA(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}

	for(int i = 0; i < numQ; i++){

		vec_data.push_back(DATA(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_data.begin(),vec_data.end());

	set<SegInfo> posSET;

	for(int i = 0; i < vec_data.size(); i++){

		DATA data = vec_data[i];

		baseX = data.x; //■sort用のxを更新

		if(data.isQuery){

			if(posSET.size() == 0){

				continue;
			}
			auto at = posSET.lower_bound({0,data.y-EPS,0,0});
			if(at != posSET.begin()){


				at--;
				if(TO_R[at->ind]){

					ANS[data.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[data.poly_ind]){

				if(!data.isL){

					auto at = posSET.lower_bound({SLOPE[data.ind],SEC[data.ind]-2*EPS,(int)data.isToR,data.ind});

					//■誤差対策
					for(int k = 0; k < MAX; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == data.ind){
							posSET.erase(at);
							break;
						}
						at++;
					}
				}

				continue;
			}

			if(COUNT[data.poly_ind] == 0){ //最も左の点
				COUNT[data.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる

				if(posSET.size() > 0){

					auto at = posSET.lower_bound({0,data.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;

						if(TO_R[at->ind]){

							POL_DEL[data.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(data.isL){

				posSET.insert({SLOPE[data.ind],SEC[data.ind],(int)data.isToR,data.ind});

			}else{  //右の点

				auto at = posSET.lower_bound({SLOPE[data.ind],SEC[data.ind]-2*EPS,(int)data.isToR,data.ind});


				//■誤差対策
				for(int k = 0; k < MAX; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == data.ind){
						posSET.erase(at);
						break;
					}
					at++;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 1
time_ms: 3510
memory_kb: 184448
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct DATA{
	DATA(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	DATA(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct DATA& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(isL != arg.isL){

			if(isL){ //■削除命令を先に処理する

				return false;
			}else{

				return true;
			}

		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct SegInfo{
	SegInfo(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	SegInfo(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct SegInfo &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct SegInfo &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_DATAENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_DATAENT;
}

//傾きを求める関数
double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}

	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue; //■時計回りでないならSKIP
				tmp_S *= -1;

				poly_S[V.size()] = tmp_S;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
			}
		}
	}

	vector<DATA> vec_data;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			vec_data.push_back(DATA(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_data.push_back(DATA(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}

	for(int i = 0; i < numQ; i++){

		vec_data.push_back(DATA(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_data.begin(),vec_data.end());

	set<SegInfo> posSET;

	for(int i = 0; i < vec_data.size(); i++){

		DATA data = vec_data[i];

		baseX = data.x; //■sort用のxを更新

		if(data.isQuery){

			if(posSET.size() == 0){

				continue;
			}
			auto at = posSET.lower_bound({0,data.y-EPS,0,0});
			if(at != posSET.begin()){


				at--;
				if(TO_R[at->ind]){

					ANS[data.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[data.poly_ind]){

				if(!data.isL){

					auto at = posSET.lower_bound({SLOPE[data.ind],SEC[data.ind]-2*EPS,(int)data.isToR,data.ind});

					//■誤差対策
					for(int k = 0; k < 5; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == data.ind){
							posSET.erase(at);
							break;
						}
						at++;
					}
				}

				continue;
			}

			if(COUNT[data.poly_ind] == 0){ //最も左の点
				COUNT[data.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる

				if(posSET.size() > 0){

					auto at = posSET.lower_bound({0,data.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;

						if(TO_R[at->ind]){

							POL_DEL[data.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(data.isL){

				posSET.insert({SLOPE[data.ind],SEC[data.ind],(int)data.isToR,data.ind});

			}else{  //右の点

				auto at = posSET.lower_bound({SLOPE[data.ind],SEC[data.ind]-2*EPS,(int)data.isToR,data.ind});


				//■誤差対策
				for(int k = 0; k < 5; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == data.ind){
						posSET.erase(at);
						break;
					}
					at++;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 1
time_ms: 3600
memory_kb: 185008
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct DATA{
	DATA(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	DATA(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct DATA& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(isL != arg.isL){

			if(isL){ //■削除命令を先に処理する

				return false;
			}else{

				return true;
			}

		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct SegInfo{
	SegInfo(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	SegInfo(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct SegInfo &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct SegInfo &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_DATAENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_DATAENT;
}

//傾きを求める関数
double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}

	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue; //■時計回りでないならSKIP
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
			}
		}
	}


	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<DATA> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			vec_seg.push_back(DATA(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(DATA(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}

	for(int i = 0; i < numQ; i++){

		vec_seg.push_back(DATA(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());

	set<SegInfo> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		DATA seg = vec_seg[i];

		baseX = seg.x; //■sort用のxを更新

		if(seg.isQuery){

			if(posSET.size() == 0){

				continue;
			}
			auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
			if(at != posSET.begin()){


				at--;
				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});

					//■誤差対策
					for(int k = 0; k < 5; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							posSET.erase(at);
							break;
						}
						at++;
					}
				}

				continue;
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる

				if(posSET.size() > 0){

					auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});


				//■誤差対策
				for(int k = 0; k < 5; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						posSET.erase(at);
						break;
					}
					at++;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 1
time_ms: 3450
memory_kb: 184484
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(isL != arg.isL){

			if(isL){ //■削除命令を先に処理する

				return false;
			}else{

				return true;
			}

		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct Naoto{
	Naoto(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	Naoto(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct Naoto &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct Naoto &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

//傾きを求める関数
double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}

	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue; //■時計回りでないならSKIP
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
			}
		}
	}


	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}

	for(int i = 0; i < numQ; i++){

		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());

	set<Naoto> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		baseX = seg.x; //■sort用のxを更新

		if(seg.isQuery){

			if(posSET.size() == 0){

				continue;
			}
			auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
			if(at != posSET.begin()){


				at--;
				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});

					//■誤差対策
					for(int k = 0; k < 5; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							posSET.erase(at);
							break;
						}
						at++;
					}
				}

				continue;
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる

				if(posSET.size() > 0){

					auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});


				//■誤差対策
				for(int k = 0; k < 5; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						posSET.erase(at);
						break;
					}
					at++;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 1
time_ms: 3410
memory_kb: 184736
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(isL != arg.isL){

			if(isL){

				return false;
			}else{

				return true;
			}

		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct Naoto{
	Naoto(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	Naoto(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct Naoto &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct Naoto &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}
	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());






	ll sum = 0;

	set<Naoto> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		baseX = seg.x;

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			if(posSET.size() == 0){

				continue;
			}
			//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
			auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
			if(at != posSET.begin()){


				at--;
				if(DEBUG){

					printf("\n線分と交差します\n");
					LINE[at->ind].outPut();

					for(Naoto nao: posSET){

						int ind = nao.ind;
						double y = SLOPE[ind]*seg.x + SEC[ind];
						if(y < seg.y){

							printf("線分%dと交差します y:%.3lf\n",ind,y);
												LINE[ind].outPut();
							if(TO_R[ind]){

								printf("右向き\n");
							}else{

								printf("左向き\n");
							}

						}
					}
					//return 0;
				}

				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

			//■■
			/*double max_y = -HUGE_NUM;
			int tmp_ind = -1;

			for(Naoto nao: posSET){

				int ind = nao.ind;
				double y = SLOPE[ind]*seg.x + SEC[ind];
				if(y > seg.y+EPS)break;

				if(y+EPS < max_y){

					printf("■■順番が狂ってる クエリ点(%.3lf,%.3lf)\n",seg.x,seg.y);
					printf("前の線分[%d] slope:%.3lf max_y:%.3lf ",tmp_ind,SLOPE[tmp_ind],max_y);
					LINE[tmp_ind].outPut();

					printf("今回の線分[%d] slope:%.3lf y:%.3lf ",ind,SLOPE[ind],y);
					LINE[ind].outPut();

					auto dk =  posSET.lower_bound({0,seg.y-EPS,0,0});
					dk--;
					printf("二分探索の線分 ");
					LINE[dk->ind].outPut();

					double pug = SLOPE[dk->ind]*seg.x + SEC[dk->ind];
					printf("二分探索のy:%.3lf\n",pug);

					return 0;
				}else{

					max_y = y;
					tmp_ind = ind;
				}
			}

			if(tmp_ind != -1 && TO_R[tmp_ind] == 1){

				ANS[seg.ind] = 1;
			}*/

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					if(DEBUG){

						printf("★★線分%dを消します\n",seg.ind);
					}

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
					int inu = 0;

					for(int k = 0; k < 5; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							inu = 1;
							posSET.erase(at);
							break;
						}
						at++;
					}

					if(DEBUG && inu == 0){
						printf("見つかりません\n");
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				if(posSET.size() > 0){

					//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
					auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;
						if(DEBUG){

							printf("線分と交差します\n");
							LINE[at->ind].outPut();
						}

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				if(DEBUG){

					printf("線分%dを追加します\n",seg.ind);
				}

				//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				if(DEBUG){

					printf("★★線分%dを消します\n",seg.ind);

					double y = SLOPE[seg.ind]*seg.x + SEC[seg.ind];
					printf("y:%.3lf\n",y);
				}

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
				int inu = 0;

				if(DEBUG){

					if(at == posSET.end()){

						printf("いきなり最後\n");
					}else{

						printf("最初に出会ったのは%d\n",at->ind);
					}
				}

				for(int k = 0; k < 5; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						inu = 1;
						posSET.erase(at);
						break;
					}
					at++;
				}

				if(DEBUG && inu == 0){
					printf("見つかりません 順に線分を列挙します\n");
					for(Naoto nao: posSET){

						printf("線分%d\n",nao.ind);
					}
					return 0;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 1
time_ms: 3420
memory_kb: 194448
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct Naoto{
	Naoto(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	Naoto(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct Naoto &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct Naoto &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}
	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());






	ll sum = 0;

	set<Naoto> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		baseX = seg.x;

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			if(posSET.size() == 0){

				continue;
			}
			//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
			auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
			if(at != posSET.begin()){


				/*if(DEBUG){
				double max_y = -HUGE_NUM;
				int pre_ind = -1;

				for(Naoto nao: posSET){

					int ind = nao.ind;
					double y = SLOPE[ind]*seg.x + SEC[ind];
					if(y < seg.y){
						if(y > max_y){

							pre_ind = ind;
							max_y = y;
						}else if(fabs(y-max_y) < EPS){

							printf("■同じ線分が2個入ってる\n");
							return 0;

						}else{

							printf("■順番が狂ってる\n");
							printf("pre_y:%.3lf pre_slope:%.3lf 線分pre ",max_y,SLOPE[pre_ind]);
							LINE[pre_ind].outPut();
							printf("y:%.3lf slope:%.3lf 今回 ",y,SLOPE[ind]);
							LINE[ind].outPut();
							return 0;
						}
						pre_ind = ind;

						printf("線分%dと交差します y:%.3lf\n",ind,y);
											LINE[ind].outPut();
						if(TO_R[ind]){

							printf("右向き\n");
						}else{

							printf("左向き\n");
						}

					}
				}
				}*/

				at--;
				if(DEBUG){

					printf("\n線分と交差します\n");
					LINE[at->ind].outPut();

					for(Naoto nao: posSET){

						int ind = nao.ind;
						double y = SLOPE[ind]*seg.x + SEC[ind];
						if(y < seg.y){

							printf("線分%dと交差します y:%.3lf\n",ind,y);
												LINE[ind].outPut();
							if(TO_R[ind]){

								printf("右向き\n");
							}else{

								printf("左向き\n");
							}

						}
					}
					//return 0;
				}

				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					if(DEBUG){

						printf("★★線分%dを消します\n",seg.ind);
					}

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
					int inu = 0;

					for(int k = 0; k < 5; k++){
						if(at != posSET.begin()){

							at--;
						}else{

							break;
						}

					}

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							inu = 1;
							posSET.erase(at);
							break;
						}
						at++;
					}

					if(DEBUG && inu == 0){
						printf("見つかりません\n");
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				if(posSET.size() > 0){

					//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
					auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;
						if(DEBUG){

							printf("線分と交差します\n");
							LINE[at->ind].outPut();
						}

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				if(DEBUG){

					printf("線分%dを追加します\n",seg.ind);
				}

				//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				if(DEBUG){

					printf("★★線分%dを消します\n",seg.ind);

					double y = SLOPE[seg.ind]*seg.x + SEC[seg.ind];
					printf("y:%.3lf\n",y);
				}

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
				int inu = 0;

				if(DEBUG){

					if(at == posSET.end()){

						printf("いきなり最後\n");
					}else{

						printf("最初に出会ったのは%d\n",at->ind);
					}
				}

				for(int k = 0; k < 5; k++){
					if(at != posSET.begin()){

						at--;
					}else{

						break;
					}

				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						inu = 1;
						posSET.erase(at);
						break;
					}
					at++;
				}

				if(DEBUG && inu == 0){
					printf("見つかりません 順に線分を列挙します\n");
					for(Naoto nao: posSET){

						printf("線分%d\n",nao.ind);
					}
					return 0;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.39080459770114945
time_ms: 300
memory_kb: 142144
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-4
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct Naoto{
	Naoto(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	Naoto(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct Naoto &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct Naoto &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}
	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());






	ll sum = 0;

	set<Naoto> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		baseX = seg.x;

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			if(posSET.size() == 0){

				continue;
			}
			//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
			auto at = posSET.lower_bound({0,seg.y-2*EPS,0,0});
			if(at != posSET.begin()){


				/*if(DEBUG){
				double max_y = -HUGE_NUM;
				int pre_ind = -1;

				for(Naoto nao: posSET){

					int ind = nao.ind;
					double y = SLOPE[ind]*seg.x + SEC[ind];
					if(y < seg.y){
						if(y > max_y){

							pre_ind = ind;
							max_y = y;
						}else if(fabs(y-max_y) < EPS){

							printf("■同じ線分が2個入ってる\n");
							return 0;

						}else{

							printf("■順番が狂ってる\n");
							printf("pre_y:%.3lf pre_slope:%.3lf 線分pre ",max_y,SLOPE[pre_ind]);
							LINE[pre_ind].outPut();
							printf("y:%.3lf slope:%.3lf 今回 ",y,SLOPE[ind]);
							LINE[ind].outPut();
							return 0;
						}
						pre_ind = ind;

						printf("線分%dと交差します y:%.3lf\n",ind,y);
											LINE[ind].outPut();
						if(TO_R[ind]){

							printf("右向き\n");
						}else{

							printf("左向き\n");
						}

					}
				}
				}*/

				at--;
				if(DEBUG){

					printf("\n線分と交差します\n");
					LINE[at->ind].outPut();

					for(Naoto nao: posSET){

						int ind = nao.ind;
						double y = SLOPE[ind]*seg.x + SEC[ind];
						if(y < seg.y){

							printf("線分%dと交差します y:%.3lf\n",ind,y);
												LINE[ind].outPut();
							if(TO_R[ind]){

								printf("右向き\n");
							}else{

								printf("左向き\n");
							}

						}
					}
					//return 0;
				}

				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					if(DEBUG){

						printf("★★線分%dを消します\n",seg.ind);
					}

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
					int inu = 0;

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							inu = 1;
							posSET.erase(at);
							break;
						}
						at++;
					}

					if(DEBUG && inu == 0){
						printf("見つかりません\n");
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				if(posSET.size() > 0){

					//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
					auto at = posSET.lower_bound({0,seg.y-2*EPS,0,0});
					if(at != posSET.begin()){

						at--;
						if(DEBUG){

							printf("線分と交差します\n");
							LINE[at->ind].outPut();
						}

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				if(DEBUG){

					printf("線分%dを追加します\n",seg.ind);
				}

				//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				if(DEBUG){

					printf("★★線分%dを消します\n",seg.ind);

					double y = SLOPE[seg.ind]*seg.x + SEC[seg.ind];
					printf("y:%.3lf\n",y);
				}

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
				int inu = 0;

				if(DEBUG){

					if(at == posSET.end()){

						printf("いきなり最後\n");
					}else{

						printf("最初に出会ったのは%d\n",at->ind);
					}
				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						inu = 1;
						posSET.erase(at);
						break;
					}
					at++;
				}

				if(DEBUG && inu == 0){
					printf("見つかりません 順に線分を列挙します\n");
					for(Naoto nao: posSET){

						printf("線分%d\n",nao.ind);
					}
					return 0;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.39080459770114945
time_ms: 300
memory_kb: 141312
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct Naoto{
	Naoto(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	Naoto(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct Naoto &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct Naoto &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}
	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());






	ll sum = 0;

	set<Naoto> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		baseX = seg.x;

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			if(posSET.size() == 0){

				continue;
			}
			//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
			auto at = posSET.lower_bound({0,seg.y-2*EPS,0,0});
			if(at != posSET.begin()){


				/*if(DEBUG){
				double max_y = -HUGE_NUM;
				int pre_ind = -1;

				for(Naoto nao: posSET){

					int ind = nao.ind;
					double y = SLOPE[ind]*seg.x + SEC[ind];
					if(y < seg.y){
						if(y > max_y){

							pre_ind = ind;
							max_y = y;
						}else if(fabs(y-max_y) < EPS){

							printf("■同じ線分が2個入ってる\n");
							return 0;

						}else{

							printf("■順番が狂ってる\n");
							printf("pre_y:%.3lf pre_slope:%.3lf 線分pre ",max_y,SLOPE[pre_ind]);
							LINE[pre_ind].outPut();
							printf("y:%.3lf slope:%.3lf 今回 ",y,SLOPE[ind]);
							LINE[ind].outPut();
							return 0;
						}
						pre_ind = ind;

						printf("線分%dと交差します y:%.3lf\n",ind,y);
											LINE[ind].outPut();
						if(TO_R[ind]){

							printf("右向き\n");
						}else{

							printf("左向き\n");
						}

					}
				}
				}*/

				at--;
				if(DEBUG){

					printf("\n線分と交差します\n");
					LINE[at->ind].outPut();

					for(Naoto nao: posSET){

						int ind = nao.ind;
						double y = SLOPE[ind]*seg.x + SEC[ind];
						if(y < seg.y){

							printf("線分%dと交差します y:%.3lf\n",ind,y);
												LINE[ind].outPut();
							if(TO_R[ind]){

								printf("右向き\n");
							}else{

								printf("左向き\n");
							}

						}
					}
					//return 0;
				}

				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					if(DEBUG){

						printf("★★線分%dを消します\n",seg.ind);
					}

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
					int inu = 0;

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							inu = 1;
							posSET.erase(at);
							break;
						}
						at++;
					}

					if(DEBUG && inu == 0){
						printf("見つかりません\n");
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				if(posSET.size() > 0){

					//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
					auto at = posSET.lower_bound({0,seg.y-2*EPS,0,0});
					if(at != posSET.begin()){

						at--;
						if(DEBUG){

							printf("線分と交差します\n");
							LINE[at->ind].outPut();
						}

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				if(DEBUG){

					printf("線分%dを追加します\n",seg.ind);
				}

				//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				if(DEBUG){

					printf("★★線分%dを消します\n",seg.ind);

					double y = SLOPE[seg.ind]*seg.x + SEC[seg.ind];
					printf("y:%.3lf\n",y);
				}

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
				int inu = 0;

				if(DEBUG){

					if(at == posSET.end()){

						printf("いきなり最後\n");
					}else{

						printf("最初に出会ったのは%d\n",at->ind);
					}
				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						inu = 1;
						posSET.erase(at);
						break;
					}
					at++;
				}

				if(DEBUG && inu == 0){
					printf("見つかりません 順に線分を列挙します\n");
					for(Naoto nao: posSET){

						printf("線分%d\n",nao.ind);
					}
					return 0;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.39080459770114945
time_ms: 300
memory_kb: 141260
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


double baseX;


struct Naoto{
	Naoto(){

		slope = sec = 0;
		to_r = ind = 0;
	}
	Naoto(double arg_slope,double arg_sec,int arg_to_r,int arg_ind){
		slope = arg_slope;
		sec = arg_sec;
		to_r = arg_to_r;
		ind = arg_ind;
	}

	bool operator<(const struct Naoto &arg) const{


		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return y1 < y2;

		}else{

			if(slope > 0 && arg.slope > 0){

				return slope < arg.slope;
			}else if(slope < 0 && arg.slope < 0){

				return slope < arg.slope; //■追加するときに右下がりが端点を共有してるときは、左上の点で、傾きが小さい方が下、
			}else if(slope < 0 && arg.slope > 0){

				return true;

			}else{ //slope > 0 && arg.slope < 0

				return false;
			}
		}
	}
	bool operator==(const struct Naoto &arg) const{

		double y1 = slope*baseX + sec;
		double y2 = arg.slope*baseX + arg.sec;

		if(fabs(y1-y2) > EPS){

			return false;;

		}else if(fabs(slope-arg.slope) > EPS){

			return false;
		}else{

			return true;
		}
	}

	double slope,sec;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
map<int,int> e_count;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
			e_count[ind] += 1;
		}
	}

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			auto bt = e_count.find(ind);
			if(!isToR && bt->second >= 2)continue; //右向きの辺があるなら左向きは不要


			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}
	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());






	ll sum = 0;

	set<Naoto> posSET;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		baseX = seg.x;

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			if(posSET.size() == 0){

				continue;
			}
			//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
			auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
			if(at != posSET.begin()){


				/*if(DEBUG){
				double max_y = -HUGE_NUM;
				int pre_ind = -1;

				for(Naoto nao: posSET){

					int ind = nao.ind;
					double y = SLOPE[ind]*seg.x + SEC[ind];
					if(y < seg.y){
						if(y > max_y){

							pre_ind = ind;
							max_y = y;
						}else if(fabs(y-max_y) < EPS){

							printf("■同じ線分が2個入ってる\n");
							return 0;

						}else{

							printf("■順番が狂ってる\n");
							printf("pre_y:%.3lf pre_slope:%.3lf 線分pre ",max_y,SLOPE[pre_ind]);
							LINE[pre_ind].outPut();
							printf("y:%.3lf slope:%.3lf 今回 ",y,SLOPE[ind]);
							LINE[ind].outPut();
							return 0;
						}
						pre_ind = ind;

						printf("線分%dと交差します y:%.3lf\n",ind,y);
											LINE[ind].outPut();
						if(TO_R[ind]){

							printf("右向き\n");
						}else{

							printf("左向き\n");
						}

					}
				}
				}*/

				at--;
				if(DEBUG){

					printf("\n線分と交差します\n");
					LINE[at->ind].outPut();

					for(Naoto nao: posSET){

						int ind = nao.ind;
						double y = SLOPE[ind]*seg.x + SEC[ind];
						if(y < seg.y){

							printf("線分%dと交差します y:%.3lf\n",ind,y);
												LINE[ind].outPut();
							if(TO_R[ind]){

								printf("右向き\n");
							}else{

								printf("左向き\n");
							}

						}
					}
					//return 0;
				}

				if(TO_R[at->ind]){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					if(DEBUG){

						printf("★★線分%dを消します\n",seg.ind);
					}

					auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
					int inu = 0;

					while(at != posSET.end()){

						if(at->ind == seg.ind){
							inu = 1;
							posSET.erase(at);
							break;
						}
						at++;
					}

					if(DEBUG && inu == 0){
						printf("見つかりません\n");
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				if(posSET.size() > 0){

					//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
					auto at = posSET.lower_bound({0,seg.y-EPS,0,0});
					if(at != posSET.begin()){

						at--;
						if(DEBUG){

							printf("線分と交差します\n");
							LINE[at->ind].outPut();
						}

						if(TO_R[at->ind]){

							POL_DEL[seg.poly_ind] = true;
							continue;
						}
					}
				}
			}

			if(seg.isL){

				if(DEBUG){

					printf("線分%dを追加します\n",seg.ind);
				}

				//POS(double arg_slope,double arg_sec,int arg_to_r,int arg_ind)
				posSET.insert({SLOPE[seg.ind],SEC[seg.ind],(int)seg.isToR,seg.ind});

			}else{  //右の点

				if(DEBUG){

					printf("★★線分%dを消します\n",seg.ind);

					double y = SLOPE[seg.ind]*seg.x + SEC[seg.ind];
					printf("y:%.3lf\n",y);
				}

				auto at = posSET.lower_bound({SLOPE[seg.ind],SEC[seg.ind]-2*EPS,(int)seg.isToR,seg.ind});
				int inu = 0;

				if(DEBUG){

					if(at == posSET.end()){

						printf("いきなり最後\n");
					}else{

						printf("最初に出会ったのは%d\n",at->ind);
					}
				}

				while(at != posSET.end()){

					if(at->ind == seg.ind){
						inu = 1;
						posSET.erase(at);
						break;
					}
					at++;
				}

				if(DEBUG && inu == 0){
					printf("見つかりません 順に線分を列挙します\n");
					for(Naoto nao: posSET){

						printf("線分%d\n",nao.ind);
					}
					return 0;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.39080459770114945
time_ms: 300
memory_kb: 141236
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};

//右上がり
struct R_UP{
	R_UP(){

		to_r = ind = 0;
	}
	R_UP(Point a,Point b,int arg_to_r,int arg_ind){

		line = Line(a,b);
		to_r = arg_to_r;
		ind = arg_ind;
	}
	bool operator<(const struct R_UP& arg) const{

		double slope1 = (line.p[1].y-line.p[0].y)/(line.p[1].x-line.p[0].x);
		double slope2 = (arg.line.p[1].y-arg.line.p[0].y)/(arg.line.p[1].x-arg.line.p[0].x);

		double sec1 = line.p[0].y-slope1*line.p[0].x; //return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
		double sec2 = arg.line.p[0].y-slope2*arg.line.p[0].x;



		double mini = min(line.p[0].x,line.p[1].x);
		double maxi = max(line.p[0].x,line.p[1].x);

		double arg_mini = min(arg.line.p[0].x,arg.line.p[1].x);
		double arg_maxi = max(arg.line.p[0].x,arg.line.p[1].x);

		//printf("自分:%d adj:%d mini:%.3lf maxi:%.3lf arg_mini:%.3lf arg_maxi:%.3lf\n",ind,arg.ind,mini,maxi,arg_mini,arg_maxi);

		if(maxi+EPS < arg_mini){

			//printf("左の方がランク高\n");
			return maxi < arg_mini;

		}else if(arg_maxi+EPS < mini){

			//printf("右の方がランク高\n");
			return mini < arg_maxi;

		}else{ //■区間に重なりがある

			if(line == arg.line){

				//printf("線分同じ\n");
				return to_r > arg.to_r; //■右向きの方がランクが高い
			}

			if((line.p[0] == arg.line.p[0])||(line.p[0] == arg.line.p[1])||
					(line.p[1] == arg.line.p[0])||(line.p[1] == arg.line.p[1])){ //端点が同じ

				//printf("■端点同じ\n");

				Line a = line;
				if(a.p[0].x > a.p[1].x){

					swap(a.p[0],a.p[1]);
				}
				Line b = arg.line;
				if(b.p[0].x > b.p[1].x){

					swap(b.p[0],b.p[1]);
				}

				if(a.p[0] == b.p[0]){

					return slope1 > slope2;

				}else if(a.p[1] == b.p[1]){

					return slope1 < slope2;

				}else{

					return mini < arg_mini;
				}
			}

			double x = max(mini,arg_mini);

			double y1 = slope1*x + sec1;
			double y2 = slope2*x + sec2;

			//printf("y1:%.3lf y2:%.3lf\n",y1,y2);

			return y1 > y2;
		}
	}

	Line line;
	int ind,to_r;
};

//右下がり
struct R_DOWN{
	R_DOWN(){

		to_r = ind = 0;
	}
	R_DOWN(Point a,Point b,int arg_to_r,int arg_ind){

		line = Line(a,b);
		to_r = arg_to_r;
		ind = arg_ind;
	}
	bool operator<(const struct R_DOWN& arg) const{

		double slope1 = (line.p[1].y-line.p[0].y)/(line.p[1].x-line.p[0].x);
		double slope2 = (arg.line.p[1].y-arg.line.p[0].y)/(arg.line.p[1].x-arg.line.p[0].x);

		double sec1 = line.p[0].y-slope1*line.p[0].x;
		double sec2 = arg.line.p[0].y-slope2*arg.line.p[0].x;



		double mini = min(line.p[0].x,line.p[1].x);
		double maxi = max(line.p[0].x,line.p[1].x);

		double arg_mini = min(arg.line.p[0].x,arg.line.p[1].x);
		double arg_maxi = max(arg.line.p[0].x,arg.line.p[1].x);

		//printf("自分:%d adj:%d mini:%.3lf maxi:%.3lf arg_mini:%.3lf arg_maxi:%.3lf\n",ind,arg.ind,mini,maxi,arg_mini,arg_maxi);

		if(maxi+EPS < arg_mini){

			//printf("左の方がランク高\n");
			return maxi < arg_mini;

		}else if(arg_maxi+EPS < mini){

			//printf("右の方がランク高\n");
			return mini < arg_maxi;

		}else{ //■区間に重なりがある

			if(line == arg.line){

				//printf("線分同じ\n");
				return to_r > arg.to_r; //■右向きの方がランクが高い
			}

			if((line.p[0] == arg.line.p[0])||(line.p[0] == arg.line.p[1])||
					(line.p[1] == arg.line.p[0])||(line.p[1] == arg.line.p[1])){ //端点が同じ

				//printf("■端点同じ\n");

				Line a = line;
				if(a.p[0].x > a.p[1].x){

					swap(a.p[0],a.p[1]);
				}
				Line b = arg.line;
				if(b.p[0].x > b.p[1].x){

					swap(b.p[0],b.p[1]);
				}

				if(a.p[1] == b.p[1]){ //右下の点が等しい場合

					//printf("slopeが小さい方が聖\n");
					return slope1 < slope2; //傾きが小さい方がランク高

				}else if(a.p[0] == b.p[0]){ //左上の点が等しい場合

					//printf("slopeが大きい方が正\n");
					//return slope1 < slope2;■
					return slope1 > slope2;

				}else{ //片方の右下と片方の左上が等しい

					//printf("左の方が聖\n");
					return mini < arg_mini;
				}
			}

			double x = max(mini,arg_mini);

			double y1 = slope1*x + sec1;
			double y2 = slope2*x + sec2;

			//printf("y1:%.3lf y2:%.3lf\n",y1,y2);

			return y1 > y2;
		}
	}

	Line line;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
		}
	}

	vector<R_UP> ru;
	vector<R_DOWN> rd;

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			if(l.p[0].y < l.p[1].y){ //右上がり

				R_UP tmp_r;
				tmp_r.line = l;
				tmp_r.to_r = (int)isToR;
				tmp_r.ind = LINE.size();
				ru.push_back(tmp_r);

			}else{ //右下がり

				R_DOWN tmp_d;
				tmp_d.line = l;
				tmp_d.to_r = (int)isToR;
				tmp_d.ind = LINE.size();
				rd.push_back(tmp_d);
			}

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}


	if(ru.size() > 0){
		sort(ru.begin(),ru.end());
	}
	if(rd.size() > 0){

		sort(rd.begin(),rd.end());
	}

	int number = 1e6-1;

	map<int,int> RANK,revRANK;

	if(DEBUG){
	printf("\n\n右上がり\n");
	}
	for(int i = 0; i < ru.size(); i++){

		if(DEBUG){
		printf("■線分:%d\n",ru[i].ind);
		LINE[ru[i].ind].outPut();
		printf("のランクは%d\n",number);
		}
		RANK[ru[i].ind] = number; //辺にランクをつける
		revRANK[number--] = ru[i].ind;
	}

	if(DEBUG){
	printf("\n右下がり\n");
	}
	for(int i = 0; i < rd.size(); i++){

		if(DEBUG){
			printf("■線分:%d\n",rd[i].ind);
		LINE[rd[i].ind].outPut();
		printf("のランクは%d slope:%.3lf\n",number,SLOPE[rd[i].ind]);
		}
		RANK[rd[i].ind] = number; //辺にランクをつける
		revRANK[number--] = rd[i].ind;
	}


	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());


	set<int> SU,SD;

	ll sum = 0;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			//■真下にある辺の向きを見る(右向きなら多角形の中)
			double y1 = -HUGE_NUM,y2 = -HUGE_NUM;
			int dir1 = -1,dir2 = -1;


			double naoto = HUGE_NUM;


			//■ランク順に並んでいるはずなので二分探索
			if(SU.size() > 0){
				int left = 0;
				int right = 1e6;
				int mid = (left+right)/2;
				int rank = -1;

				/*while(left <= right){

					auto at = SU.lower_bound(mid);
					if(at == SU.end()){
						right = mid-1;
						mid = (left+right)/2;
						continue;
					}

					int id = revRANK[*at];

					double y = SLOPE[id]*seg.x + SEC[id];
					if(y < seg.y){

						rank = mid;
						left = mid+1;
						y1 = y;

					}else{

						right = mid-1;
					}
					mid = (left+right)/2;
				}*/



				for(int inu: SU){

					int p = revRANK[inu];

					double y = SLOPE[p]*seg.x + SEC[p];
					if(y < seg.y){

						if(naoto > seg.y-y){
							naoto = seg.y-y;
							y1 = y;

							if(TO_R[p]){

								dir1 = 1;

							}else{

								dir1 = 0;
							}
						}else if(fabs(naoto-(seg.y-y)) < EPS){

							if(TO_R[p]){

								dir1 = 1;

							}
						}
					}
				}

				/*if(rank != -1){

					int tmp_id = revRANK[rank]; //■真下の辺
					if(DEBUG){
						printf("右上がり\n");
						printf("\n線分%d\n",tmp_id);
						LINE[tmp_id].outPut();
						printf("と交差\n");
					}
					if(TO_R[tmp_id]){

						dir1 = 1;
					}
				}*/
			}

			if(DEBUG){

				printf("SD.size():%lld\n",SD.size());
				for(int inu: SD){

					printf("線分%dを格納\n",revRANK[inu]);
				}
				printf("\n--------------\n");
			}

			if(SD.size() > 0){
				int left = 0;
				int right = 1e6;
				int mid = (left+right)/2;
				int rank = -1;

				for(int inu: SD){

					int p = revRANK[inu];

					double y = SLOPE[p]*seg.x + SEC[p];
					if(y < seg.y){

						if(naoto > seg.y-y){
							naoto = seg.y-y;
							y2 = y;

							if(TO_R[p]){

								dir2 = 1;

							}else{

								dir2 = 0;
							}
						}else if(fabs(naoto-(seg.y-y)) < EPS){

							if(TO_R[p]){

								dir2 = 1;

							}
						}
					}
				}

				/*while(left <= right){

					auto at = SD.lower_bound(mid);
					if(at == SD.end()){
						right = mid-1;
						mid = (left+right)/2;
						continue;
					}

					int id = revRANK[*at];

					double y = SLOPE[id]*seg.x + SEC[id];
					if(y < seg.y){

						rank = mid;
						left = mid+1;
						y2 = y;

					}else{

						right = mid-1;
					}
					mid = (left+right)/2;
				}

				if(rank != -1){
					int tmp_id = revRANK[rank]; //■真下の辺
					if(DEBUG){
						printf("右下がり\n");
						printf("\n線分%d\n",tmp_id);
						LINE[tmp_id].outPut();
						printf("と交差\n");
					}
					if(TO_R[tmp_id]){

						dir2 = 1;
					}
				}*/
			}

			if(DEBUG){
			printf("クエリ%d dir1:%d dir2:%d y1:%.3lf y2:%.3lf\n",seg.ind,dir1,dir2,y1,y2);
			}

			if(dir1 == -1 && dir2 == -1)continue;

			if(y1 > y2){

				if(dir1 == 1){

					ANS[seg.ind] = 1;
				}

			}else{ //y1 < y2

				if(dir2 == 1){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					//printf("線分%dを消します\n",seg.ind);

					if(is_r_up[seg.ind]){

						SU.erase(RANK[seg.ind]);
					}else{

						SD.erase(RANK[seg.ind]);
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				//■真下にある辺の向きを見る(右向きなら多角形の中)
				int last = -1;
				double min_dist = HUGE_NUM;
				int c_ind = -1;

				for(int tmp_rank: SU){

					int id = revRANK[tmp_rank];

					if(POL_DEL[POLY_IND[id]])continue;


					Line work_line = LINE[id];
					if(base_line == work_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					double slope = SLOPE[id];
					double sec = SEC[id];

					double y = slope*seg.x + sec;
					if(y > seg.y+EPS)break;
					double tmp_dist = seg.y-y;

					if(tmp_dist+EPS < min_dist){
						min_dist = tmp_dist;

						if(TO_R[id]){

							last = 1;
							c_ind = POLY_IND[id];

						}else{

							last = 0;
						}
					}else if(fabs(tmp_dist-min_dist) < EPS){

						if(TO_R[id]){

							last = 1;
						}

					}
				}

				for(int tmp_rank: SD){

					int id = revRANK[tmp_rank];

					if(POL_DEL[POLY_IND[id]])continue;


					Line work_line = LINE[id];
					if(base_line == work_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					double slope = SLOPE[id];
					double sec = SEC[id];

					double y = slope*seg.x + sec;
					if(y > seg.y+EPS)break;
					double tmp_dist = seg.y-y;

					if(tmp_dist+EPS < min_dist){
						min_dist = tmp_dist;

						if(TO_R[id]){

							last = 1;
							c_ind = POLY_IND[id];

						}else{

							last = 0;
						}
					}else if(fabs(tmp_dist-min_dist) < EPS){

						if(TO_R[id]){

							last = 1;
						}
					}
				}

				if(last == 1){ //■他のポリゴンに含まれている

					if(DEBUG){
					printf("他のポリゴンに含まれています\n");
					printf("\nポリゴン%dはポリゴン%dに含まれています min_dist:%.3lf\n",seg.poly_ind,c_ind,min_dist);

					}
					POL_DEL[seg.poly_ind] = true;

					continue;
				}
			}

			if(seg.isL){

				if(DEBUG){
				printf("線分%dを追加します ランク%d\n",seg.ind,RANK[seg.ind]);
				}

				if(is_r_up[seg.ind]){

					if(DEBUG){
					printf("右上がり\n");
					}
					SU.insert(RANK[seg.ind]);

				}else{

					if(DEBUG){
					printf("右下がり\n");
					}
					SD.insert(RANK[seg.ind]);
				}

			}else{  //右の点

				if(DEBUG){
				printf("線分%dを消します ランク:%d\n",seg.ind,RANK[seg.ind]);
				}

				if(is_r_up[seg.ind]){
					if(DEBUG){
					printf("右上がり\n");
					}

					SU.erase(RANK[seg.ind]);

				}else{

					if(DEBUG){
					printf("右下がり\n");
					}

					SD.erase(RANK[seg.ind]);
				}
			}
		}
	}


	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.3333333333333333
time_ms: 20
memory_kb: 88348
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};

//右上がり
struct R_UP{
	R_UP(){

		to_r = ind = 0;
	}
	R_UP(Point a,Point b,int arg_to_r,int arg_ind){

		line = Line(a,b);
		to_r = arg_to_r;
		ind = arg_ind;
	}
	bool operator<(const struct R_UP& arg) const{

		double slope1 = (line.p[1].y-line.p[0].y)/(line.p[1].x-line.p[0].x);
		double slope2 = (arg.line.p[1].y-arg.line.p[0].y)/(arg.line.p[1].x-arg.line.p[0].x);

		double sec1 = line.p[0].y-slope1*line.p[0].x; //return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
		double sec2 = arg.line.p[0].y-slope2*arg.line.p[0].x;



		double mini = min(line.p[0].x,line.p[1].x);
		double maxi = max(line.p[0].x,line.p[1].x);

		double arg_mini = min(arg.line.p[0].x,arg.line.p[1].x);
		double arg_maxi = max(arg.line.p[0].x,arg.line.p[1].x);

		//printf("自分:%d adj:%d mini:%.3lf maxi:%.3lf arg_mini:%.3lf arg_maxi:%.3lf\n",ind,arg.ind,mini,maxi,arg_mini,arg_maxi);

		if(maxi+EPS < arg_mini){

			//printf("左の方がランク高\n");
			return maxi < arg_mini;

		}else if(arg_maxi+EPS < mini){

			//printf("右の方がランク高\n");
			return mini < arg_maxi;

		}else{ //■区間に重なりがある

			if(line == arg.line){

				//printf("線分同じ\n");
				return to_r > arg.to_r; //■右向きの方がランクが高い
			}

			if((line.p[0] == arg.line.p[0])||(line.p[0] == arg.line.p[1])||
					(line.p[1] == arg.line.p[0])||(line.p[1] == arg.line.p[1])){ //端点が同じ

				//printf("■端点同じ\n");

				Line a = line;
				if(a.p[0].x > a.p[1].x){

					swap(a.p[0],a.p[1]);
				}
				Line b = arg.line;
				if(b.p[0].x > b.p[1].x){

					swap(b.p[0],b.p[1]);
				}

				if(a.p[0] == b.p[0]){

					return slope1 > slope2;

				}else if(a.p[1] == b.p[1]){

					return slope1 < slope2;

				}else{

					return mini < arg_mini;
				}
			}

			double x = max(mini,arg_mini);

			double y1 = slope1*x + sec1;
			double y2 = slope2*x + sec2;

			//printf("y1:%.3lf y2:%.3lf\n",y1,y2);

			return y1 > y2;
		}
	}

	Line line;
	int ind,to_r;
};

//右下がり
struct R_DOWN{
	R_DOWN(){

		to_r = ind = 0;
	}
	R_DOWN(Point a,Point b,int arg_to_r,int arg_ind){

		line = Line(a,b);
		to_r = arg_to_r;
		ind = arg_ind;
	}
	bool operator<(const struct R_DOWN& arg) const{

		double slope1 = (line.p[1].y-line.p[0].y)/(line.p[1].x-line.p[0].x);
		double slope2 = (arg.line.p[1].y-arg.line.p[0].y)/(arg.line.p[1].x-arg.line.p[0].x);

		double sec1 = line.p[0].y-slope1*line.p[0].x;
		double sec2 = arg.line.p[0].y-slope2*arg.line.p[0].x;



		double mini = min(line.p[0].x,line.p[1].x);
		double maxi = max(line.p[0].x,line.p[1].x);

		double arg_mini = min(arg.line.p[0].x,arg.line.p[1].x);
		double arg_maxi = max(arg.line.p[0].x,arg.line.p[1].x);

		//printf("自分:%d adj:%d mini:%.3lf maxi:%.3lf arg_mini:%.3lf arg_maxi:%.3lf\n",ind,arg.ind,mini,maxi,arg_mini,arg_maxi);

		if(maxi+EPS < arg_mini){

			//printf("左の方がランク高\n");
			return maxi < arg_mini;

		}else if(arg_maxi+EPS < mini){

			//printf("右の方がランク高\n");
			return mini < arg_maxi;

		}else{ //■区間に重なりがある

			if(line == arg.line){

				//printf("線分同じ\n");
				return to_r > arg.to_r; //■右向きの方がランクが高い
			}

			if((line.p[0] == arg.line.p[0])||(line.p[0] == arg.line.p[1])||
					(line.p[1] == arg.line.p[0])||(line.p[1] == arg.line.p[1])){ //端点が同じ

				//printf("■端点同じ\n");

				Line a = line;
				if(a.p[0].x > a.p[1].x){

					swap(a.p[0],a.p[1]);
				}
				Line b = arg.line;
				if(b.p[0].x > b.p[1].x){

					swap(b.p[0],b.p[1]);
				}

				if(a.p[1] == b.p[1]){ //右下の点が等しい場合

					//printf("slopeが小さい方が聖\n");
					return slope1 < slope2; //傾きが小さい方がランク高

				}else if(a.p[0] == b.p[0]){ //左上の点が等しい場合

					//printf("slopeが大きい方が正\n");
					//return slope1 < slope2;■
					return slope1 > slope2;

				}else{ //片方の右下と片方の左上が等しい

					//printf("左の方が聖\n");
					return mini < arg_mini;
				}
			}

			double x = max(mini,arg_mini);

			double y1 = slope1*x + sec1;
			double y2 = slope2*x + sec2;

			//printf("y1:%.3lf y2:%.3lf\n",y1,y2);

			return y1 > y2;
		}
	}

	Line line;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
		}
	}

	vector<R_UP> ru;
	vector<R_DOWN> rd;

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			if(l.p[0].y < l.p[1].y){ //右上がり

				R_UP tmp_r;
				tmp_r.line = l;
				tmp_r.to_r = (int)isToR;
				tmp_r.ind = LINE.size();
				ru.push_back(tmp_r);

			}else{ //右下がり

				R_DOWN tmp_d;
				tmp_d.line = l;
				tmp_d.to_r = (int)isToR;
				tmp_d.ind = LINE.size();
				rd.push_back(tmp_d);
			}

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}


	if(ru.size() > 0){
		sort(ru.begin(),ru.end());
	}
	if(rd.size() > 0){

		sort(rd.begin(),rd.end());
	}

	int number = 1e6-1;

	map<int,int> RANK,revRANK;

	if(DEBUG){
	printf("\n\n右上がり\n");
	}
	for(int i = 0; i < ru.size(); i++){

		if(DEBUG){
		printf("■線分:%d\n",ru[i].ind);
		LINE[ru[i].ind].outPut();
		printf("のランクは%d\n",number);
		}
		RANK[ru[i].ind] = number; //辺にランクをつける
		revRANK[number--] = ru[i].ind;
	}

	if(DEBUG){
	printf("\n右下がり\n");
	}
	for(int i = 0; i < rd.size(); i++){

		if(DEBUG){
			printf("■線分:%d\n",rd[i].ind);
		LINE[rd[i].ind].outPut();
		printf("のランクは%d slope:%.3lf\n",number,SLOPE[rd[i].ind]);
		}
		RANK[rd[i].ind] = number; //辺にランクをつける
		revRANK[number--] = rd[i].ind;
	}


	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());


	set<int> SU,SD;

	ll sum = 0;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			//■真下にある辺の向きを見る(右向きなら多角形の中)
			double y1 = -HUGE_NUM,y2 = -HUGE_NUM;
			int dir1 = -1,dir2 = -1;


			double minhi = HUGE_NUM;


			//■ランク順に並んでいるはずなので二分探索
			if(SU.size() > 0){
				int left = 0;
				int right = 1e6;
				int mid = (left+right)/2;
				int rank = -1;

				/*while(left <= right){

					auto at = SU.lower_bound(mid);
					if(at == SU.end()){
						right = mid-1;
						mid = (left+right)/2;
						continue;
					}

					int id = revRANK[*at];

					double y = SLOPE[id]*seg.x + SEC[id];
					if(y < seg.y){

						rank = mid;
						left = mid+1;
						y1 = y;

					}else{

						right = mid-1;
					}
					mid = (left+right)/2;
				}*/



				for(int inu: SU){

					int p = revRANK[inu];

					double y = SLOPE[p]*seg.x + SEC[p];
					if(y < seg.y){

						if(minhi > seg.y-y){
							minhi = seg.y-y;
							y1 = y;

							if(TO_R[p]){

								dir1 = 1;

							}else{

								dir1 = 0;
							}
						}
					}
				}

				/*if(rank != -1){

					int tmp_id = revRANK[rank]; //■真下の辺
					if(DEBUG){
						printf("右上がり\n");
						printf("\n線分%d\n",tmp_id);
						LINE[tmp_id].outPut();
						printf("と交差\n");
					}
					if(TO_R[tmp_id]){

						dir1 = 1;
					}
				}*/
			}

			if(DEBUG){

				printf("SD.size():%lld\n",SD.size());
				for(int inu: SD){

					printf("線分%dを格納\n",revRANK[inu]);
				}
				printf("\n--------------\n");
			}

			if(SD.size() > 0){
				int left = 0;
				int right = 1e6;
				int mid = (left+right)/2;
				int rank = -1;

				for(int inu: SD){

					int p = revRANK[inu];

					double y = SLOPE[p]*seg.x + SEC[p];
					if(y < seg.y){

						if(minhi > seg.y-y){
							minhi = seg.y-y;
							y2 = y;

							if(TO_R[p]){

								dir2 = 1;

							}else{

								dir2 = 0;
							}
						}
					}
				}

				/*while(left <= right){

					auto at = SD.lower_bound(mid);
					if(at == SD.end()){
						right = mid-1;
						mid = (left+right)/2;
						continue;
					}

					int id = revRANK[*at];

					double y = SLOPE[id]*seg.x + SEC[id];
					if(y < seg.y){

						rank = mid;
						left = mid+1;
						y2 = y;

					}else{

						right = mid-1;
					}
					mid = (left+right)/2;
				}

				if(rank != -1){
					int tmp_id = revRANK[rank]; //■真下の辺
					if(DEBUG){
						printf("右下がり\n");
						printf("\n線分%d\n",tmp_id);
						LINE[tmp_id].outPut();
						printf("と交差\n");
					}
					if(TO_R[tmp_id]){

						dir2 = 1;
					}
				}*/
			}

			if(DEBUG){
			printf("クエリ%d dir1:%d dir2:%d y1:%.3lf y2:%.3lf\n",seg.ind,dir1,dir2,y1,y2);
			}

			if(dir1 == -1 && dir2 == -1)continue;


			if(y1 > y2){

				if(dir1 == 1){

					ANS[seg.ind] = 1;
				}

			}else{ //y1 < y2

				if(dir2 == 1){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					//printf("線分%dを消します\n",seg.ind);

					if(is_r_up[seg.ind]){

						SU.erase(RANK[seg.ind]);
					}else{

						SD.erase(RANK[seg.ind]);
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				//■真下にある辺の向きを見る(右向きなら多角形の中)
				int last = -1;
				double min_dist = HUGE_NUM;
				int c_ind = -1;

				for(int tmp_rank: SU){

					int id = revRANK[tmp_rank];

					if(POL_DEL[POLY_IND[id]])continue;


					Line work_line = LINE[id];
					if(base_line == work_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					double slope = SLOPE[id];
					double sec = SEC[id];

					double y = slope*seg.x + sec;
					if(y > seg.y+EPS)break;
					double tmp_dist = seg.y-y;

					if(tmp_dist+EPS < min_dist || fabs(tmp_dist-min_dist) < EPS){
						min_dist = tmp_dist;

						if(TO_R[id]){

							last = 1;
							c_ind = POLY_IND[id];

						}else{

							last = 0;
						}
					}/*else if(fabs(tmp_dist-min_dist) < EPS){

						if(TO_R[id]){

							last = 1;
						}

					}*/
				}

				for(int tmp_rank: SD){

					int id = revRANK[tmp_rank];

					if(POL_DEL[POLY_IND[id]])continue;


					Line work_line = LINE[id];
					if(base_line == work_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					double slope = SLOPE[id];
					double sec = SEC[id];

					double y = slope*seg.x + sec;
					if(y > seg.y+EPS)break;
					double tmp_dist = seg.y-y;

					if(tmp_dist+EPS < min_dist || fabs(tmp_dist-min_dist) < EPS){
						min_dist = tmp_dist;

						if(TO_R[id]){

							last = 1;
							c_ind = POLY_IND[id];

						}else{

							last = 0;
						}
					}/*else if(fabs(tmp_dist-min_dist) < EPS){

						if(TO_R[id]){

							last = 1;
						}
					}*/
				}

				if(last == 1){ //■他のポリゴンに含まれている

					if(DEBUG){
					printf("他のポリゴンに含まれています\n");
					printf("\nポリゴン%dはポリゴン%dに含まれています min_dist:%.3lf\n",seg.poly_ind,c_ind,min_dist);

					}
					POL_DEL[seg.poly_ind] = true;

					continue;
				}
			}

			if(seg.isL){

				if(DEBUG){
				printf("線分%dを追加します ランク%d\n",seg.ind,RANK[seg.ind]);
				}

				if(is_r_up[seg.ind]){

					if(DEBUG){
					printf("右上がり\n");
					}
					SU.insert(RANK[seg.ind]);

				}else{

					if(DEBUG){
					printf("右下がり\n");
					}
					SD.insert(RANK[seg.ind]);
				}

			}else{  //右の点

				if(DEBUG){
				printf("線分%dを消します ランク:%d\n",seg.ind,RANK[seg.ind]);
				}

				if(is_r_up[seg.ind]){
					if(DEBUG){
					printf("右上がり\n");
					}

					SU.erase(RANK[seg.ind]);

				}else{

					if(DEBUG){
					printf("右下がり\n");
					}

					SD.erase(RANK[seg.ind]);
				}
			}
		}
	}


	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.3333333333333333
time_ms: 20
memory_kb: 88028
final_rank: 17

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-6
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};

//右上がり
struct R_UP{
	R_UP(){

		to_r = ind = 0;
	}
	R_UP(Point a,Point b,int arg_to_r,int arg_ind){

		line = Line(a,b);
		to_r = arg_to_r;
		ind = arg_ind;
	}
	bool operator<(const struct R_UP& arg) const{

		double slope1 = (line.p[1].y-line.p[0].y)/(line.p[1].x-line.p[0].x);
		double slope2 = (arg.line.p[1].y-arg.line.p[0].y)/(arg.line.p[1].x-arg.line.p[0].x);

		double sec1 = line.p[0].y-slope1*line.p[0].x; //return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
		double sec2 = arg.line.p[0].y-slope2*arg.line.p[0].x;



		double mini = min(line.p[0].x,line.p[1].x);
		double maxi = max(line.p[0].x,line.p[1].x);

		double arg_mini = min(arg.line.p[0].x,arg.line.p[1].x);
		double arg_maxi = max(arg.line.p[0].x,arg.line.p[1].x);

		//printf("自分:%d adj:%d mini:%.3lf maxi:%.3lf arg_mini:%.3lf arg_maxi:%.3lf\n",ind,arg.ind,mini,maxi,arg_mini,arg_maxi);

		if(maxi+EPS < arg_mini){

			//printf("左の方がランク高\n");
			return maxi < arg_mini;

		}else if(arg_maxi+EPS < mini){

			//printf("右の方がランク高\n");
			return mini < arg_maxi;

		}else{ //■区間に重なりがある

			if(line == arg.line){

				//printf("線分同じ\n");
				return to_r > arg.to_r; //■右向きの方がランクが高い
			}

			if((line.p[0] == arg.line.p[0])||(line.p[0] == arg.line.p[1])||
					(line.p[1] == arg.line.p[0])||(line.p[1] == arg.line.p[1])){ //端点が同じ

				//printf("■端点同じ\n");

				Line a = line;
				if(a.p[0].x > a.p[1].x){

					swap(a.p[0],a.p[1]);
				}
				Line b = arg.line;
				if(b.p[0].x > b.p[1].x){

					swap(b.p[0],b.p[1]);
				}

				if(a.p[0] == b.p[0]){

					return slope1 > slope2;

				}else if(a.p[1] == b.p[1]){

					return slope1 < slope2;

				}else{

					return mini < arg_mini;
				}
			}

			double x = max(mini,arg_mini);

			double y1 = slope1*x + sec1;
			double y2 = slope2*x + sec2;

			//printf("y1:%.3lf y2:%.3lf\n",y1,y2);

			return y1 > y2;
		}
	}

	Line line;
	int ind,to_r;
};

//右下がり
struct R_DOWN{
	R_DOWN(){

		to_r = ind = 0;
	}
	R_DOWN(Point a,Point b,int arg_to_r,int arg_ind){

		line = Line(a,b);
		to_r = arg_to_r;
		ind = arg_ind;
	}
	bool operator<(const struct R_DOWN& arg) const{

		double slope1 = (line.p[1].y-line.p[0].y)/(line.p[1].x-line.p[0].x);
		double slope2 = (arg.line.p[1].y-arg.line.p[0].y)/(arg.line.p[1].x-arg.line.p[0].x);

		double sec1 = line.p[0].y-slope1*line.p[0].x;
		double sec2 = arg.line.p[0].y-slope2*arg.line.p[0].x;



		double mini = min(line.p[0].x,line.p[1].x);
		double maxi = max(line.p[0].x,line.p[1].x);

		double arg_mini = min(arg.line.p[0].x,arg.line.p[1].x);
		double arg_maxi = max(arg.line.p[0].x,arg.line.p[1].x);

		//printf("自分:%d adj:%d mini:%.3lf maxi:%.3lf arg_mini:%.3lf arg_maxi:%.3lf\n",ind,arg.ind,mini,maxi,arg_mini,arg_maxi);

		if(maxi+EPS < arg_mini){

			//printf("左の方がランク高\n");
			return maxi < arg_mini;

		}else if(arg_maxi+EPS < mini){

			//printf("右の方がランク高\n");
			return mini < arg_maxi;

		}else{ //■区間に重なりがある

			if(line == arg.line){

				//printf("線分同じ\n");
				return to_r > arg.to_r; //■右向きの方がランクが高い
			}

			if((line.p[0] == arg.line.p[0])||(line.p[0] == arg.line.p[1])||
					(line.p[1] == arg.line.p[0])||(line.p[1] == arg.line.p[1])){ //端点が同じ

				//printf("■端点同じ\n");

				Line a = line;
				if(a.p[0].x > a.p[1].x){

					swap(a.p[0],a.p[1]);
				}
				Line b = arg.line;
				if(b.p[0].x > b.p[1].x){

					swap(b.p[0],b.p[1]);
				}

				if(a.p[1] == b.p[1]){ //右下の点が等しい場合

					//printf("slopeが小さい方が聖\n");
					return slope1 < slope2; //傾きが小さい方がランク高

				}else if(a.p[0] == b.p[0]){ //左上の点が等しい場合

					//printf("slopeが大きい方が正\n");
					//return slope1 < slope2;■
					return slope1 > slope2;

				}else{ //片方の右下と片方の左上が等しい

					//printf("左の方が聖\n");
					return mini < arg_mini;
				}
			}

			double x = max(mini,arg_mini);

			double y1 = slope1*x + sec1;
			double y2 = slope2*x + sec2;

			//printf("y1:%.3lf y2:%.3lf\n",y1,y2);

			return y1 > y2;
		}
	}

	Line line;
	int ind,to_r;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],is_r_up[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
int num_EMAP = 0;
double SLOPE[SIZE],SEC[SIZE];



int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


//辺の切片を求める関数
double calc_section(Line tmp_line){

	double tmp_slope = calc_slope(tmp_line);

	return tmp_line.p[0].y-tmp_slope*tmp_line.p[0].x;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		ind = (ind-1+G[node].size())%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next_e_ind) > 0){

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> work_nodes;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				work_nodes.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = work_nodes;

			return;
		}

		SET.insert(next_e_ind);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}

int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(e_ind);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(POL_DEL[k])continue;
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	map<pair<int,int>,int> DUP;
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			DUP[make_pair(i,ind)] += 1;
		}
	}

	vector<R_UP> ru;
	vector<R_DOWN> rd;

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;

		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			auto at = DUP.find(make_pair(i,ind));
			if(at->second >= 2){
				if(DEBUG){

					printf("辺");
					point[from].debug();
					point[to].debug();
					printf("を追加しない\n");
				}
				continue; //■1つの辺が複数回使われる点は棒状なので削除
			}

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();

			}else{

				ind_R[ind] = LINE.size();
			}

			Line l = Line(point[from],point[to]);

			double tmp_section = calc_section(l);

			SLOPE[LINE.size()] = tmp_slope;
			SEC[LINE.size()] = tmp_section;

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			if(l.p[0].x > l.p[1].x){

				swap(l.p[0],l.p[1]);
			}

			is_r_up[LINE.size()] = (l.p[0].y < l.p[1].y);

			if(l.p[0].y < l.p[1].y){ //右上がり

				R_UP tmp_r;
				tmp_r.line = l;
				tmp_r.to_r = (int)isToR;
				tmp_r.ind = LINE.size();
				ru.push_back(tmp_r);

			}else{ //右下がり

				R_DOWN tmp_d;
				tmp_d.line = l;
				tmp_d.to_r = (int)isToR;
				tmp_d.ind = LINE.size();
				rd.push_back(tmp_d);
			}

			LINE.push_back(Line(point[from],point[to]));
			POLY_IND.push_back(i);
			TO_R.push_back(isToR);
		}
	}


	if(ru.size() > 0){
		sort(ru.begin(),ru.end());
	}
	if(rd.size() > 0){

		sort(rd.begin(),rd.end());
	}

	int number = 1e6-1;

	map<int,int> RANK,revRANK;

	if(DEBUG){
	printf("\n\n右上がり\n");
	}
	for(int i = 0; i < ru.size(); i++){

		if(DEBUG){
		printf("■線分:%d\n",ru[i].ind);
		LINE[ru[i].ind].outPut();
		printf("のランクは%d\n",number);
		}
		RANK[ru[i].ind] = number; //辺にランクをつける
		revRANK[number--] = ru[i].ind;
	}

	if(DEBUG){
	printf("\n右下がり\n");
	}
	for(int i = 0; i < rd.size(); i++){

		if(DEBUG){
			printf("■線分:%d\n",rd[i].ind);
		LINE[rd[i].ind].outPut();
		printf("のランクは%d slope:%.3lf\n",number,SLOPE[rd[i].ind]);
		}
		RANK[rd[i].ind] = number; //辺にランクをつける
		revRANK[number--] = rd[i].ind;
	}


	if(DEBUG){
	printf("LINE.size():%lld\n",LINE.size());
	}

	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());


	set<int> SU,SD;

	ll sum = 0;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		if(seg.isQuery){

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			//■真下にある辺の向きを見る(右向きなら多角形の中)
			double y1 = -HUGE_NUM,y2 = -HUGE_NUM;
			int dir1 = -1,dir2 = -1;


			double minhi = HUGE_NUM;


			//■ランク順に並んでいるはずなので二分探索
			if(SU.size() > 0){
				int left = 0;
				int right = 1e6;
				int mid = (left+right)/2;
				int rank = -1;

				/*while(left <= right){

					auto at = SU.lower_bound(mid);
					if(at == SU.end()){
						right = mid-1;
						mid = (left+right)/2;
						continue;
					}

					int id = revRANK[*at];

					double y = SLOPE[id]*seg.x + SEC[id];
					if(y < seg.y){

						rank = mid;
						left = mid+1;
						y1 = y;

					}else{

						right = mid-1;
					}
					mid = (left+right)/2;
				}*/



				for(int inu: SU){

					int p = revRANK[inu];

					double y = SLOPE[p]*seg.x + SEC[p];
					if(y < seg.y){

						if(minhi > seg.y-y){
							minhi = seg.y-y;
							y1 = y;

							if(TO_R[p]){

								dir1 = 1;

							}else{

								dir1 = 0;
							}
						}
					}
				}

				/*if(rank != -1){

					int tmp_id = revRANK[rank]; //■真下の辺
					if(DEBUG){
						printf("右上がり\n");
						printf("\n線分%d\n",tmp_id);
						LINE[tmp_id].outPut();
						printf("と交差\n");
					}
					if(TO_R[tmp_id]){

						dir1 = 1;
					}
				}*/
			}

			if(DEBUG){

				printf("SD.size():%lld\n",SD.size());
				for(int inu: SD){

					printf("線分%dを格納\n",revRANK[inu]);
				}
				printf("\n--------------\n");
			}

			if(SD.size() > 0){
				int left = 0;
				int right = 1e6;
				int mid = (left+right)/2;
				int rank = -1;

				for(int inu: SD){

					int p = revRANK[inu];

					double y = SLOPE[p]*seg.x + SEC[p];
					if(y < seg.y){

						if(minhi > seg.y-y){
							minhi = seg.y-y;
							y2 = y;

							if(TO_R[p]){

								dir2 = 1;

							}else{

								dir2 = 0;
							}
						}
					}
				}

				/*while(left <= right){

					auto at = SD.lower_bound(mid);
					if(at == SD.end()){
						right = mid-1;
						mid = (left+right)/2;
						continue;
					}

					int id = revRANK[*at];

					double y = SLOPE[id]*seg.x + SEC[id];
					if(y < seg.y){

						rank = mid;
						left = mid+1;
						y2 = y;

					}else{

						right = mid-1;
					}
					mid = (left+right)/2;
				}

				if(rank != -1){
					int tmp_id = revRANK[rank]; //■真下の辺
					if(DEBUG){
						printf("右下がり\n");
						printf("\n線分%d\n",tmp_id);
						LINE[tmp_id].outPut();
						printf("と交差\n");
					}
					if(TO_R[tmp_id]){

						dir2 = 1;
					}
				}*/
			}

			if(DEBUG){
			printf("クエリ%d dir1:%d dir2:%d y1:%.3lf y2:%.3lf\n",seg.ind,dir1,dir2,y1,y2);
			}

			if(dir1 == -1 && dir2 == -1)continue;


			if(y1 > y2){

				if(dir1 == 1){

					ANS[seg.ind] = 1;
				}

			}else{ //y1 < y2

				if(dir2 == 1){

					ANS[seg.ind] = 1;
				}
			}

		}else{ //線分

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					//printf("線分%dを消します\n",seg.ind);

					if(is_r_up[seg.ind]){

						SU.erase(RANK[seg.ind]);
					}else{

						SD.erase(RANK[seg.ind]);
					}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分%dです\n",seg.poly_ind,seg.ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line base_line = LINE[seg.ind];


				//■真下にある辺の向きを見る(右向きなら多角形の中)
				int last = -1;
				double min_dist = HUGE_NUM;
				int c_ind = -1;

				for(int tmp_rank: SU){

					int id = revRANK[tmp_rank];

					if(POL_DEL[POLY_IND[id]])continue;


					Line work_line = LINE[id];
					if(base_line == work_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					double slope = SLOPE[id];
					double sec = SEC[id];

					double y = slope*seg.x + sec;
					if(y > seg.y+EPS)break;
					double tmp_dist = seg.y-y;

					if(tmp_dist+EPS < min_dist){
						min_dist = tmp_dist;

						if(TO_R[id]){

							last = 1;
							c_ind = POLY_IND[id];

						}else{

							last = 0;
						}
					}else if(fabs(tmp_dist-min_dist) < EPS){

						if(TO_R[id]){

							last = 1;
						}

					}
				}

				for(int tmp_rank: SD){

					int id = revRANK[tmp_rank];

					if(POL_DEL[POLY_IND[id]])continue;


					Line work_line = LINE[id];
					if(base_line == work_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					double slope = SLOPE[id];
					double sec = SEC[id];

					double y = slope*seg.x + sec;
					if(y > seg.y+EPS)break;
					double tmp_dist = seg.y-y;

					if(tmp_dist+EPS < min_dist){
						min_dist = tmp_dist;

						if(TO_R[id]){

							last = 1;
							c_ind = POLY_IND[id];

						}else{

							last = 0;
						}
					}else if(fabs(tmp_dist-min_dist) < EPS){

						if(TO_R[id]){

							last = 1;
						}
					}
				}

				if(last == 1){ //■他のポリゴンに含まれている

					if(DEBUG){
					printf("他のポリゴンに含まれています\n");
					printf("\nポリゴン%dはポリゴン%dに含まれています min_dist:%.3lf\n",seg.poly_ind,c_ind,min_dist);

					}
					POL_DEL[seg.poly_ind] = true;

					continue;
				}
			}

			if(seg.isL){

				if(DEBUG){
				printf("線分%dを追加します ランク%d\n",seg.ind,RANK[seg.ind]);
				}

				if(is_r_up[seg.ind]){

					if(DEBUG){
					printf("右上がり\n");
					}
					SU.insert(RANK[seg.ind]);

				}else{

					if(DEBUG){
					printf("右下がり\n");
					}
					SD.insert(RANK[seg.ind]);
				}

			}else{  //右の点

				if(DEBUG){
				printf("線分%dを消します ランク:%d\n",seg.ind,RANK[seg.ind]);
				}

				if(is_r_up[seg.ind]){
					if(DEBUG){
					printf("右上がり\n");
					}

					SU.erase(RANK[seg.ind]);

				}else{

					if(DEBUG){
					printf("右下がり\n");
					}

					SD.erase(RANK[seg.ind]);
				}
			}
		}
	}


	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.3333333333333333
time_ms: 20
memory_kb: 88076
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
//#define EPS 0.000000001


#define EPS 1e-9
#define SIZE 300005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	bool operator==(const struct Line &arg) const{

		return (p[0] == arg.p[0] && p[1] == arg.p[1])||(p[0] == arg.p[1] && p[1] == arg.p[0]);
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};



struct SEGM{
	SEGM(double arg_x,double arg_y,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind,double arg_slope,double arg_pol_s,int arg_e_ind){
		x = arg_x;
		y = arg_y;
		isQuery = arg_isQuery;
		isL = arg_isL;
		ind = arg_ind;
		isToR = arg_isToR;
		poly_ind = arg_poly_ind;
		slope = arg_slope;
		pol_s = arg_pol_s;
		e_ind = arg_e_ind;
	}
	SEGM(){
		x = y = slope = pol_s = 0;
		isQuery = isL = isToR = false;
		ind = poly_ind = e_ind = 0;
	}
	bool operator<(const struct SEGM& arg) const{

		if(fabs(x-arg.x) > EPS){

			return x < arg.x;
		}else if(fabs(pol_s-arg.pol_s) > EPS){
			return pol_s > arg.pol_s;
		}else{

			return y < arg.y;
		}
	}
	double x,y,slope,pol_s;
	bool isQuery,isL,isToR;
	int ind,poly_ind,e_ind;
};

struct Info{
	Info(int arg_node,int arg_pre){
		node = arg_node;
		pre = arg_pre;
	}
	Info(){

		node = pre = 0;
	}

	int node,pre;
};


int N,M,numQ;
Line line[SIZE];
Point point[SIZE],q_point[SIZE],RU[SIZE],LD[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES,NODES;
vector<vector<int>> V_N;
set<int> SET;
Polygon POL;
bool CONNECT,DEL[SIZE],visited[SIZE],check[SIZE],POL_DEL[SIZE],ADD_CHECK[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;
int A[SIZE],B[SIZE],COUNT[SIZE],ANS[SIZE];
double X[SIZE],Y[SIZE];
double QX[SIZE],QY[SIZE],poly_S[SIZE];
vector<Line> LINE;
int ind_L[SIZE],ind_R[SIZE];
bool add_L[SIZE],add_R[SIZE];
vector<bool> TO_R;
vector<int> POLY_IND;
map<pair<int,int>,int> POS;
int table[SIZE];
vector<pair<double,int>> vec_S[SIZE];
map<pair<int,int>,int> EMAP;
int num_EMAP = 0;


int getIndex(int a,int b){

	auto at = EMAP.find(make_pair(a,b));
	if(at == EMAP.end()){

		EMAP[make_pair(a,b)] = num_EMAP++;
	}
	return EMAP[make_pair(a,b)];
}


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//■■直線ではなく、線分の交差判定■■
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}



//■■■■■
bool DEBUG = false;

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

double calc_S(Polygon g){

	int N = g.size();
	double ret = 0;

	for(int i = 0; i < g.size(); i++){
		ret += cross(g[i],g[(i+1)%N]);
	}
	return ret/2.0;
}


void bfs(int first_pre,int first_node){

	queue<Info> Q;
	Q.push(Info(first_node,first_pre)); //■スタックオーバーフロー対策

	while(!Q.empty()){

		Info info = Q.front();
		Q.pop();

		int pre = info.pre;
		int node = info.node;

		int ind = POS.find(make_pair(node,pre))->second; //preがG[node]における何番目か
		//ind = (ind-1+G[node].size())%G[node].size();
		ind = (ind+1)%G[node].size();

		int next = G[node][ind];
		if(next == pre)return;

		//printf("node:%d pre:%d next:%d\n",node,pre,next);

		int next_e_ind = MAP[make_pair(node,G[node][ind])];
		if(visited[next_e_ind]){
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}
			return;
		}

		if(SET.count(next) > 0){ //■点始まり点終わり

			if(SET.size() == 2)return;

			CONNECT = true;
			//図形が完成した場合、訪問済みの辺は再訪しない
			for(int i = 0; i < EDGES.size(); i++){

				visited[EDGES[i]] = true;
			}

			Polygon work;
			vector<int> t_v;

			//■■最初にnextに到達するまでの点は削除する
			bool FLG = false;
			for(int i = 0; i < POL.size(); i++){
				if(POL[i] == point[next]){

					FLG = true;
				}
				if(!FLG)continue;

				work.push_back(POL[i]);
				t_v.push_back(NODES[i]);
			}

			POL.clear();
			POL = work;

			NODES.clear();
			NODES = t_v;

			return;
		}

		SET.insert(next);
		POL.push_back(point[G[node][ind]]);
		NODES.push_back(G[node][ind]);
		EDGES.push_back(next_e_ind);
		Q.push(Info(next,node));
	}
}


int main(){

	scanf("%d %d %d",&N,&M,&numQ);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X[i],&Y[i]);
	}


	for(int i = 0; i < M; i++){

		scanf("%d %d",&A[i],&B[i]);
		A[i]--;
		B[i]--;

		numDEG[A[i]]++;
		numDEG[B[i]]++;

		//所属する辺
		ON_SEG[A[i]].push_back(i);
		ON_SEG[B[i]].push_back(i);

		//辺が持つ点
		CONTAIN[i].push_back(A[i]);
		CONTAIN[i].push_back(B[i]);
	}

	for(int i = 0; i < numQ; i++){

		scanf("%lf %lf",&QX[i],&QY[i]);
	}

	//全体を微小に回転
	Point center = Point(0,0);
	double roll_rad = M_PI/180;

	if(DEBUG){

		//roll_rad = 0;
	}

	for(int i = 0; i < N; i++){

		Point tmp_p = Point(X[i],Y[i]);
		point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < numQ; i++){

		Point tmp_p = Point(QX[i],QY[i]);
		q_point[i] = rotate(center,tmp_p,roll_rad);
	}

	for(int i = 0; i < N; i++){

		DEL[i] = false;
	}

	//■■次数が1の点を含むなら、行き止まりなので辺を削除
	queue<int> que;

	for(int i = 0; i < N; i++){ //点の走査

		if(numDEG[i] == 1){

			DEL[i] = true;
			int e_ind = ON_SEG[i][0]; //点が所属する辺

			check[e_ind] = true;

			for(int k = 0; k < CONTAIN[e_ind].size(); k++){ //辺を除去するので、もう片方の端点の次数を減らす
				int p_ind = CONTAIN[e_ind][k];
				if(p_ind == i)continue;

				numDEG[p_ind]--;
				if(numDEG[p_ind] == 1){ //新しい端点になった場合

					DEL[p_ind] = true;
					que.push(p_ind);
				}
				break;
			}

		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){ //消す点が乗っている辺

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(check[seg])continue;
			check[seg] = true;

			for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

				int tmp_ind = CONTAIN[seg][a]; //点番号
				if(DEL[tmp_ind])continue;

				numDEG[tmp_ind]--;
				if(numDEG[tmp_ind] == 1){ //新しい端点になった場合

					DEL[tmp_ind] = true;
					que.push(tmp_ind);
				}
				break;
			}
		}
	}

	for(int i = 0; i < M; i++){

		int p = A[i],q = B[i];
		if(DEL[p] || DEL[q])continue;

		// //■辺に向きをつける
		REV[numE] = make_pair(p,q);
		MAP[make_pair(p,q)] = numE++;

		REV[numE] = make_pair(q,p);
		MAP[make_pair(q,p)] = numE++;

		G[p].push_back(q);
		G[q].push_back(p);
	}


	//■偏角ソート
	for(int i = 0; i < N; i++){
		if(G[i].size() == 0)continue;


		if(DEBUG){

			printf("\n点:%d\n",i);
		}

		//■偏角ソート
		vector<pair<double,int>> work;
		for(int k = 0; k < G[i].size(); k++){

			double tmp_rad = calc_rad(point[G[i][k]]-point[i]);
			work.push_back(make_pair(tmp_rad,G[i][k]));
		}
		sort(work.begin(),work.end());
		G[i].clear();
		for(int k = 0; k < work.size(); k++){

			G[i].push_back(work[k].second);
			if(DEBUG){
				printf("点%d rad;%.3lf\n",work[k].second,work[k].first);
			}
			POS[make_pair(i,work[k].second)] = k;
		}
	}

	//■ポリゴン全列挙
	vector<Polygon> V;

	for(int i = 0; i < N; i++){

		for(int k = 0; k < G[i].size(); k++){

			if(DEBUG){

				/*printf("次点");
				point[G[i][k]].debug();*/
			}

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();
			NODES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);
			NODES.push_back(i);
			NODES.push_back(G[i][k]);

			SET.insert(i);
			SET.insert(G[i][k]);

			EDGES.push_back(e_ind);

			CONNECT = false;
			bfs(i,G[i][k]);
			if(CONNECT){


				double tmp_S = calc_S(POL);

				if(tmp_S > EPS)continue;
				tmp_S *= -1;

				//POL = toCCW(POL); //CCW順にする
				reverse(POL.begin(),POL.end());
				reverse(NODES.begin(),NODES.end());

				if(DEBUG){

					printf("\n tmp_S:%.3lf\n",tmp_S);
				}

				for(int a = 0; a < EDGES.size(); a++){

					vec_S[EDGES[a]].push_back(make_pair(tmp_S,V.size())); //■ある辺に対しては、最大の面積のポリゴンだけ残す
				}

				if(DEBUG){

					printf("\n新たなポリゴン\n");
					for(int k = 0; k < POL.size(); k++){

						POL[k].debug();
					}
				}

				V.push_back(POL);
				V_N.push_back(NODES);
			}
		}
	}


	//■辺を共有しているポリゴンを消す
	for(int i = 0; i < numE; i++){
		if(vec_S[i].size() <= 1)continue;

		sort(vec_S[i].begin(),vec_S[i].end());
		double tmp_maxi = vec_S[i].back().first;

		if(DEBUG){
			printf("\n辺%d tmp_maxi:%.3lf\n",i,tmp_maxi);
			pair<int,int> e = REV.find(i)->second;

			int a = e.first;
			int b = e.second;

			point[a].debug();
			point[b].debug();
		}


		for(int k = 0; k < vec_S[i].size(); k++){

			if(fabs(vec_S[i][k].first-tmp_maxi) > 1e-5){

				POL_DEL[vec_S[i][k].second] = true;
				if(DEBUG){

					printf("S:%.3lf ポリゴン%dが消え\n",vec_S[i][k].first,vec_S[i][k].second);
				}
			}
		}
	}

	if(DEBUG){
		for(int i = 0; i < V.size(); i++){
			bool FLG = false;
			for(int k = 0; k < V.size(); k++){
				if(k == i)continue;

				for(int a = 0; a < V[k].size(); a++){
					if(contains(V[i],V[k][a]) == 2){

						printf("ポリゴン%dは%dに含まれています\n",k,i);
						FLG = true;
						break;
					}else if(contains(V[i],V[k][a]) == 1){

						printf("ポリゴン%dは%dと接しています\n",k,i);
						FLG = true;
						break;
					}
				}
				if(FLG)break;

			}
		}
	}

	/*for(int i = 0; i < numQ; i++){
				bool FLG = false;
				for(int k = 0; k < V.size(); k++){
					if(contains(V[k],q_point[i]) != 0){
						FLG = true;
						printf("Yes\n");
						break;
					}
				}
				if(!FLG){
					printf("No\n");
				}
			}
			return 0;*/



	for(int i = 0; i < V.size(); i++){

		poly_S[i] = calc_S(V[i]);
	}

	vector<SEGM> vec_seg;

	//辺追加
	//■ポリゴンの辺に向きをつける
	for(int i = 0; i < V.size(); i++){

		if(POL_DEL[i])continue;
		for(int k = 0; k < V_N[i].size(); k++){

			int from = V_N[i][k];
			int to = V_N[i][(k+1)%V_N[i].size()];

			int a = min(from,to);
			int b = max(from,to);

			int ind = getIndex(a,b);

			bool isToR = (point[from].x < point[to].x); //■辺が右向きか

			double tmp_slope = calc_slope(Line(point[from],point[to]));
			if(!isToR){

				ind_L[ind] = LINE.size();
				tmp_slope *= -1;

			}else{

				ind_R[ind] = LINE.size();
			}

			//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
			vec_seg.push_back(SEGM(point[from].x,point[from].y,false,isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));
			vec_seg.push_back(SEGM(point[to].x,point[to].y,false,!isToR,LINE.size(),isToR,i,tmp_slope,poly_S[i],ind));

			POLY_IND.push_back(i);
			LINE.push_back(Line(point[from],point[to]));
			TO_R.push_back(isToR);
		}
	}


	for(int i = 0; i < numQ; i++){

		//SEGM(double arg_x,bool arg_isQuery,bool arg_isL,int arg_ind,bool arg_isToR,int arg_poly_ind)
		vec_seg.push_back(SEGM(q_point[i].x,q_point[i].y,true,false,i,false,-1,-1,0,-1));
	}


	//■平面走査をしながら、2分探索で答えを判定
	sort(vec_seg.begin(),vec_seg.end());


	map<pair<double,int>,bool> BAR;

	for(int i = 0; i < vec_seg.size(); i++){

		SEGM seg = vec_seg[i];

		if(seg.isQuery){

			if(BAR.size() == 0){

				ANS[seg.ind] = 0;
				continue;
			}

			if(DEBUG){
			printf("\nクエリ[%d]です\n",seg.ind);
			q_point[seg.ind].debug();
			}

			Line tmp_line = Line(q_point[seg.ind],Point(seg.x,-BIG_NUM)); //縦線

			//■真下にある辺の向きを見る(右向きなら多角形の中)
			int last = -1;
			double min_dist = HUGE_NUM;

			for(auto at = BAR.begin(); at != BAR.end(); at++){

				pair<double,int> tmp = at->first;
				if(tmp.first > seg.y+10*EPS){

					break;
				}
				if(POL_DEL[POLY_IND[tmp.second]])continue;

				Line work_line = LINE[tmp.second];
				if(!is_Cross(tmp_line,work_line))continue;

				Point cross_p = calc_Cross_Point(tmp_line,work_line);
				if(DEBUG){

					printf("線分[%d]と交差します\n",tmp.second);
					work_line.outPut();
					cross_p.debug();
				}

				double tmp_dist = seg.y-cross_p.y;

				if(tmp_dist+EPS < min_dist || fabs(tmp_dist-min_dist) < EPS){
					min_dist = tmp_dist;
					if(TO_R[tmp.second]){
						if(DEBUG){

							printf("右向き\n");
						}
						last = 1;
					}else{
						if(DEBUG){

							printf("左向き\n");
						}
						last = 0;
					}
				}

			}

			if(DEBUG){
			printf("last:%d\n",last);
			}


			if(last == 1){

				ANS[seg.ind] = 1;
			}

		}else{ //線分

			Line calc_line = LINE[seg.ind];
						double mini = min(calc_line.p[0].y,calc_line.p[1].y);

			if(POL_DEL[seg.poly_ind]){

				if(!seg.isL){

					auto bt = BAR.lower_bound(make_pair(mini-EPS,-1));
									while(bt != BAR.end()){

										if(bt->first.second == seg.ind){

											BAR.erase(bt);
											break;
										}
										bt++;
									}
				}

				continue;
			}

			if(DEBUG){
			printf("\nポリゴン%dの線分です\n",seg.poly_ind);
			LINE[seg.ind].outPut();
			}

			if(COUNT[seg.poly_ind] == 0){ //最も左の点
				COUNT[seg.poly_ind]++;

				//■他のポリゴンに含まれていないか調べる
				Line tmp_line = Line(Point(seg.x,seg.y),Point(seg.x,-BIG_NUM)); //縦線
				Line base_line = LINE[seg.ind];


				//■真下にある辺の向きを見る(右向きなら多角形の中)
				int last = -1;
				int c_ind = -1;
				double min_dist = HUGE_NUM;

				for(auto at = BAR.begin(); at != BAR.end(); at++){

					pair<double,int> tmp = at->first;
					if(tmp.first > seg.y+10*EPS){

						break;
					}
					if(POL_DEL[POLY_IND[tmp.second]])continue;


					Line work_line = LINE[tmp.second];
					if(!is_Cross(tmp_line,work_line))continue;
					if(tmp_line == base_line)continue; //■線分を共有している場合はSKIP(前処理で、背中合わせのものしか残ってないはず)

					if((base_line.p[0] == tmp_line.p[0])||(base_line.p[1] == base_line.p[0]) ||
							(base_line.p[1] == tmp_line.p[0]) || (base_line.p[1] == tmp_line.p[1]))continue; //1点を共有している場合はSKIP

					Point cross_p = calc_Cross_Point(tmp_line,work_line);

					double tmp_dist = seg.y-cross_p.y;

					if(tmp_dist+EPS < min_dist || fabs(tmp_dist-min_dist) < EPS){
						min_dist = tmp_dist;

						if(TO_R[tmp.second]){

							last = 1;
							c_ind = POLY_IND[tmp.second];

						}else{

							last = 0;
						}
					}

				}

				if(last == 1){ //■他のポリゴンに含まれている

					if(DEBUG){
					printf("他のポリゴンに含まれています\n");
					printf("\nポリゴン%dはポリゴン%dに含まれています min_dist:%.3lf\n",seg.poly_ind,c_ind,min_dist);

					}
					POL_DEL[seg.poly_ind] = true;

					continue;
				}
			}

			if(TO_R[seg.ind]){

				mini += 2*EPS; //■同一直線が複数のポリゴンに、逆向きで保存されている場合あり
			}

			if(seg.isL){

				int t_i = seg.e_ind;

				if(seg.isToR){ //右向きは追加

					if(DEBUG){
					printf("右向きの辺を追加します\n");
					LINE[seg.ind].outPut();
					}
					add_R[t_i] = true;

					if(add_L[t_i]){ //左向き矢印を追加しているなら削除

						int l_i = ind_L[t_i]; //左向きのインデックス
						auto bt = BAR.lower_bound(make_pair(mini-EPS,-1));
						while(bt != BAR.end()){

							if(bt->first.second == l_i){

								BAR.erase(bt);
								break;
							}
							bt++;
						}
					}

				}else{ //左向き

					if(add_R[t_i]){
						if(DEBUG){
						printf("■左の辺を追加しません\n");
						}
						continue; //右向き矢印が入っているなら左は不要
					}
				}

				BAR[make_pair(mini,seg.ind)] = true;

			}else{  //右の点

				auto bt = BAR.lower_bound(make_pair(mini-EPS,-1));
				while(bt != BAR.end()){

					if(bt->first.second == seg.ind){

						BAR.erase(bt);
						break;
					}
					bt++;
				}
			}
		}
	}

	for(int i = 0; i < numQ; i++){
		if(ANS[i] == 0){

			printf("No\n");
		}else{

			printf("Yes\n");
		}
	}

	return 0;
}
accuracy: 0.14942528735632185
time_ms: 10
memory_kb: 81904
final_rank: 20