Problem:
Polygon-Point-Containment
For a given polygon
g
and target points
t
, print "2" if
g
contains
t
, "1" if
t
is on a segment of
g
, "0" otherwise.
g
is represented by a sequence of points
p
1
,
p
2
,...,
p
n
where line segments connecting
p
i
and
p
i+1
(1 ≤
i
≤
n-1
) are sides of the polygon. The line segment connecting
p
n
and
p
1
is also a side of the polygon.
Note that the polygon is not necessarily convex.
Input
The entire input looks like:
g
(the sequence of the points of the polygon)
q
(the number of queris = the number of target points)
1st query
2nd query
:
q
th query
g
is given by coordinates of the points
p
1
,...,
p
n
in the following format:
n
x
1
y
1
x
2
y
2
:
x
n
y
n
The first integer
n
is the number of points. The coordinate of a point
p
i
is given by two integers
x
i
and
y
i
. The coordinates of points are given in the order of counter-clockwise visit of them.
Each query consists of the coordinate of a target point
t
. The coordinate is given by two intgers
x
and
y
.
Output
For each query, print "2", "1" or "0".
Constraints
3 ≤
n
≤ 100
1 ≤
q
≤ 1000
-10000 ≤
x
i
,
y
i
≤ 10000
No point of the polygon will occur more than once.
Two sides of the polygon can intersect only at a common endpoint.
Sample Input
4
0 0
3 1
2 3
0 3
3
2 1
0 2
3 2
Sample Output
2
1
0

Submitted solutions:

code_snippet: # 1 "tmp.cpp"
#include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;
#define ll long long
#define ld long double
#define out(x) cout<<x<<'\n'
#define all(v) v.begin(),v.end()
#define rep(i,n) for(int i=0;i<(ll)(n);i++)
template<class T> inline bool chmin(T& a, T b) {if(a > b){a = b; return true;} else {return false;}};
template<class T> inline bool chmax(T& a, T b) {if(a < b){a = b; return true;} else {return false;}};
const ll INF=(1LL<<60);
const ll mod=998244353;
using Graph = vector<vector<ll>>;
using Network = vector<vector<pair<ll,ll>>>;
using Grid = vector<string>;
const vector<ll> dx = {0, 1, 0, -1};
const vector<ll> dy = {1, 0, -1, 0};
# 27 "tmp.cpp"
#ifndef M_PI
#define M_PI 3.14159265358979323846L
#endif
namespace geo {
template <typename T> struct Point;
template <typename T> struct Vector;
template <typename T> struct Line;
template <typename T> struct Segment;
template <typename T> struct Circle;
template <typename T> struct Polygon;
template <typename T> class ConvexPolygon;
template <typename T> constexpr T EPS = 0;
template <> constexpr long double EPS<long double> = 1e-9;
# 55 "tmp.cpp"
template <typename T>
int sgn(T d) {
    if (d > EPS<T>) return 1;
    if (d < -EPS<T>) return -1;
    return 0;
}
enum class CCW : int {
    COUNTER_CLOCKWISE = 1,
    CLOCKWISE = -1,
    ONLINE_BACK = 2,
    ONLINE_FRONT = -2,
    ON_SEGMENT = 0
};
enum class Containment {
    INSIDE = 0,
    OUTSIDE = 1,
    ON_BOUNDARY = 2
};
enum class CollinearHandling {
    INCLUDE,
    EXCLUDE
};
template <typename T>
struct Point {
    T x, y;
    Point() : x(0), y(0) {}
    Point(T x, T y) : x(x), y(y) {}
    Point(const Vector<T>& v) : x(v.x), y(v.y) {}
    Point<T>& operator+=(const Vector<T>& v);
    Point<T>& operator-=(const Vector<T>& v);
    Point<T>& operator*=(T s);
    Point<T>& operator/=(T s);
    T norm() const { return x * x + y * y; }
    T dist2(const Point<T>& p) const { return (*this - p).norm(); }
    long double abs() const { if constexpr (std::is_floating_point_v<T>) { return std::sqrt(static_cast<long double>(norm())); } else { static_assert(!sizeof(T), "abs() is only available for floating point types."); return 0; } }
    long double dist(const Point<T>& p) const { if constexpr (std::is_floating_point_v<T>) { return (*this - p).abs(); } else { static_assert(!sizeof(T), "dist() is only available for floating point types."); return 0; } }
    long double angle() const { if constexpr (std::is_floating_point_v<T>) { return std::atan2(y, x); } else { static_assert(!sizeof(T), "angle() is only available for floating point types."); return 0; } }
    Point<T> project(const Line<T>& l) const;
    Point<T> reflect(const Line<T>& l) const;
    Point<T> rotate(long double rad) const;
};
template <typename T>
struct Vector {
    T x, y;
    Vector() : x(0), y(0) {}
    Vector(T x, T y) : x(x), y(y) {}
    Vector(const Point<T>& p) : x(p.x), y(p.y) {}
    Vector(const Point<T>& p1, const Point<T>& p2) : x(p2.x - p1.x), y(p2.y - p1.y) {}
    Vector<T>& operator+=(const Vector<T>& v);
    Vector<T>& operator-=(const Vector<T>& v);
    Vector<T>& operator*=(T s);
    Vector<T>& operator/=(T s);
    T norm() const { return x * x + y * y; }
    long double abs() const { if constexpr (std::is_floating_point_v<T>) { return std::sqrt(static_cast<long double>(norm())); } else { static_assert(!sizeof(T), "abs() is only available for floating point types."); return 0; } }
    long double angle() const { if constexpr (std::is_floating_point_v<T>) { return std::atan2(y, x); } else { static_assert(!sizeof(T), "angle() is only available for floating point types."); return 0; } }
    Vector<T> rotate(long double rad) const;
    Vector<T> unit() const { if constexpr (std::is_floating_point_v<T>) { return *this / static_cast<T>(abs()); } else { static_assert(!sizeof(T), "unit() is only available for floating point types."); return *this; } }
    Vector<T> normal() const { if constexpr (std::is_floating_point_v<T>) { return perp().unit(); } else { static_assert(!sizeof(T), "normal() is only available for floating point types."); return *this; } }
    Vector<T> perp() const { return Vector<T>(-y, x); }
    T dot(const Vector<T>& v) const { return x * v.x + y * v.y; }
    T cross(const Vector<T>& v) const { return x * v.y - y * v.x; }
};
template <typename T> Point<T> operator+(Point<T> p, const Vector<T>& v) { return p += v; }
template <typename T> Point<T> operator-(Point<T> p, const Vector<T>& v) { return p -= v; }
template <typename T> Vector<T> operator-(const Point<T>& p1, const Point<T>& p2) { return Vector<T>(p1.x - p2.x, p1.y - p2.y); }
template <typename T> Vector<T> operator+(Vector<T> v1, const Vector<T>& v2) { return v1 += v2; }
template <typename T> Vector<T> operator-(Vector<T> v1, const Vector<T>& v2) { return v1 -= v2; }
template <typename T> Vector<T> operator*(const Vector<T>& v, T s) { auto t = v; return t *= s; }
template <typename T> Vector<T> operator*(T s, const Vector<T>& v) { return v * s; }
template <typename T> Vector<T> operator/(const Vector<T>& v, T s) { auto t = v; return t /= s; }
template <typename T> Point<T> operator+(const Point<T>& p1, const Point<T>& p2) { return Point<T>(p1.x + p2.x, p1.y + p2.y); }
template <typename T> Point<T> operator*(const Point<T>& p, T s) { return Point<T>(p.x * s, p.y * s); }
template <typename T> Point<T> operator*(T s, const Point<T>& p) { return p * s; }
template <typename T> Point<T> operator/(const Point<T>& p, T s) { return Point<T>(p.x / s, p.y / s); }
template <typename T> bool operator<(const Point<T>& p1, const Point<T>& p2) { if (p1.x != p2.x) return p1.x < p2.x; return p1.y < p2.y; }
template <typename T> bool operator==(const Point<T>& p1, const Point<T>& p2) { return p1.x == p2.x && p1.y == p2.y; }
template <typename T> bool operator!=(const Point<T>& p1, const Point<T>& p2) { return !(p1 == p2); }
template <typename T> bool operator>(const Point<T>& p1, const Point<T>& p2) { return p2 < p1; }
template <typename T> bool operator<=(const Point<T>& p1, const Point<T>& p2) { return !(p1 > p2); }
template <typename T> bool operator>=(const Point<T>& p1, const Point<T>& p2) { return !(p1 < p2); }
template <typename T> bool operator<(const Vector<T>& v1, const Vector<T>& v2) { if (v1.x != v2.x) return v1.x < v2.x; return v1.y < v2.y; }
template <typename T> bool operator==(const Vector<T>& v1, const Vector<T>& v2) { return v1.x == v2.x && v1.y == v2.y; }
template <typename T> bool operator!=(const Vector<T>& v1, const Vector<T>& v2) { return !(v1 == v2); }
template <typename T> std::istream& operator>>(std::istream& is, Point<T>& p) { is >> p.x >> p.y; return is; }
template <typename T> std::ostream& operator<<(std::ostream& os, const Point<T>& p) { os << std::fixed << std::setprecision(15) << p.x << " " << p.y; return os; }
template <typename T> std::ostream& operator<<(std::ostream& os, const Vector<T>& v) { os << std::fixed << std::setprecision(15) << v.x << " " << v.y; return os; }
template <typename T> std::string debug_format(const Point<T>& p) { std::stringstream ss; ss << std::fixed << std::setprecision(8) << "Point(" << p.x << ", " << p.y << ")"; return ss.str(); }
template <typename T> std::string debug_format(const Vector<T>& v) { std::stringstream ss; ss << std::fixed << std::setprecision(8) << "Vector[" << v.x << ", " << v.y << "]"; return ss.str(); }
template <typename T> bool eq(T a, T b) { return sgn(a - b) == 0; }
template <typename T> bool lt(T a, T b) { return sgn(a - b) < 0; }
template <typename T> bool gt(T a, T b) { return sgn(a - b) > 0; }
template <typename T> bool le(T a, T b) { return sgn(a - b) <= 0; }
template <typename T> bool ge(T a, T b) { return sgn(a - b) >= 0; }
template <typename T> bool eq(const Point<T>& p1, const Point<T>& p2) { return eq(p1.x, p2.x) && eq(p1.y, p2.y); }
template <typename T> bool eq(const Vector<T>& v1, const Vector<T>& v2) { return eq(v1.x, v2.x) && eq(v1.y, v2.y); }
template <typename T> T dot(const Vector<T>& v1, const Vector<T>& v2) { return v1.x * v2.x + v1.y * v2.y; }
template <typename T> T dot(const Point<T>& p1, const Point<T>& p2) { return p1.x * p2.x + p1.y * p2.y; }
template <typename T> T cross(const Vector<T>& v1, const Vector<T>& v2) { return v1.x * v2.y - v1.y * v2.x; }
template <typename T> T cross(const Point<T>& p1, const Point<T>& p2) { return p1.x * p2.y - p1.y * p2.x; }
# 215 "tmp.cpp"
template <typename T>
CCW ccw(const Point<T>& p0, const Point<T>& p1, const Point<T>& p2) {
    Vector<T> a = p1 - p0;
    Vector<T> b = p2 - p0;
    if (gt(cross(a, b), (T)0)) return CCW::COUNTER_CLOCKWISE;
    if (lt(cross(a, b), (T)0)) return CCW::CLOCKWISE;
    if (lt(dot(a, b), (T)0)) return CCW::ONLINE_BACK;
    if (lt(a.norm(), b.norm())) return CCW::ONLINE_FRONT;
    return CCW::ON_SEGMENT;
}
template<typename T> Point<T>& Point<T>::operator+=(const Vector<T>& v) { x += v.x; y += v.y; return *this; }
template<typename T> Point<T>& Point<T>::operator-=(const Vector<T>& v) { x -= v.x; y -= v.y; return *this; }
template<typename T> Point<T>& Point<T>::operator*=(T s) { x *= s; y *= s; return *this; }
template<typename T> Point<T>& Point<T>::operator/=(T s) { x /= s; y /= s; return *this; }
template <typename T> Point<T> Point<T>::rotate(long double rad) const { if constexpr (std::is_floating_point_v<T>) { long double cs = std::cos(rad), sn = std::sin(rad); return Point<T>(this->x * cs - this->y * sn, this->x * sn + this->y * cs); } else { static_assert(!sizeof(T), "rotate() is only available for floating point types."); return *this; } }
template<typename T> Vector<T>& Vector<T>::operator+=(const Vector<T>& v) { x += v.x; y += v.y; return *this; }
template<typename T> Vector<T>& Vector<T>::operator-=(const Vector<T>& v) { x -= v.x; y -= v.y; return *this; }
template<typename T> Vector<T>& Vector<T>::operator*=(T s) { x *= s; y *= s; return *this; }
template<typename T> Vector<T>& Vector<T>::operator/=(T s) { x /= s; y /= s; return *this; }
template <typename T> Vector<T> Vector<T>::rotate(long double rad) const { if constexpr (std::is_floating_point_v<T>) { long double cs = std::cos(rad), sn = std::sin(rad); return Vector<T>(x * cs - y * sn, x * sn + y * cs); } else { static_assert(!sizeof(T), "rotate() is only available for floating point types."); return *this; } }
}
#if defined(__GNUC__) || defined(__clang__)
namespace sub_rational {
std::ostream& operator<<(std::ostream& os, __int128_t val) {
    if (!os.good()) return os;
    if (val == 0) return os << "0";
    std::string s = "";
    bool neg = val < 0;
    if (neg) val = -val;
    while (val > 0) {
        s += (val % 10) + '0';
        val /= 10;
    }
    if (neg) s += '-';
    std::reverse(s.begin(), s.end());
    return os << s;
}
std::istream& operator>>(std::istream& is, __int128_t& val) {
    if (!is.good()) return is;
    std::string s;
    is >> s;
    val = 0;
    bool neg = s.length() > 0 && s[0] == '-';
    for (size_t i = (neg ? 1 : 0); i < s.length(); ++i) {
        if (isdigit(s[i])) {
            val = val * 10 + (s[i] - '0');
        }
    }
    if (neg) val = -val;
    return is;
}
constexpr __int128_t gcd_128(__int128_t a, __int128_t b) {
    a = a < 0 ? -a : a;
    b = b < 0 ? -b : b;
    while (b) {
        a %= b;
        std::swap(a, b);
    }
    return a;
}
}
#endif
template <typename T = long long>
class Rational {
private:
    T num;
    T den;
    using int128 = __int128_t;
    template <typename IntT>
    static constexpr IntT abs_for_rational(IntT val) {
        return val < 0 ? -val : val;
    }
    constexpr void normalize() {
        if (den == 0) {
            throw std::domain_error("Denominator is zero in Rational number");
        }
        if (den < 0) {
            num = -num;
            den = -den;
        }
        if (num == 0) {
            den = 1;
            return;
        }
        T common = std::gcd(std::abs(num), den);
        num /= common;
        den /= common;
    }
public:
    constexpr Rational(T n = 0) : num(n), den(1) {}
    constexpr Rational(T n, T d) : num(n), den(d) { normalize(); }
    template <typename U,
              typename = std::enable_if_t<std::is_arithmetic_v<U> && !std::is_same_v<U, T>>>
    constexpr Rational(U val) : num(static_cast<T>(val)), den(1) {}
#if defined(__GNUC__) || defined(__clang__)
    constexpr Rational(int128 n, int128 d) {
        if (d == 0) throw std::domain_error("Denominator is zero in Rational number");
        if (d < 0) { n = -n; d = -d; }
        if (n == 0) {
            num = 0; den = 1;
            return;
        }
        int128 common = sub_rational::gcd_128(n, d);
        n /= common;
        d /= common;
        num = static_cast<T>(n);
        den = static_cast<T>(d);
    }
#endif
    constexpr T numerator() const { return num; }
    constexpr T denominator() const { return den; }
    constexpr Rational operator+() const { return *this; }
    constexpr Rational operator-() const { return Rational(-num, den); }
    constexpr Rational& operator+=(const Rational& rhs) {
        int128 new_num = (int128)num * rhs.den + (int128)rhs.num * den;
        int128 new_den = (int128)den * rhs.den;
        *this = Rational(new_num, new_den);
        return *this;
    }
    constexpr Rational& operator-=(const Rational& rhs) {
        int128 new_num = (int128)num * rhs.den - (int128)rhs.num * den;
        int128 new_den = (int128)den * rhs.den;
        *this = Rational(new_num, new_den);
        return *this;
    }
    constexpr Rational& operator*=(const Rational& rhs) {
        Rational r1(num, rhs.den);
        Rational r2(rhs.num, den);
        int128 new_num = (int128)r1.num * r2.num;
        int128 new_den = (int128)r1.den * r2.den;
        *this = Rational(new_num, new_den);
        return *this;
    }
    constexpr Rational& operator/=(const Rational& rhs) {
        if (rhs.num == 0) throw std::domain_error("Division by zero in Rational number");
        *this *= Rational(rhs.den, rhs.num);
        return *this;
    }
    explicit operator double() const {
        return static_cast<double>(num) / den;
    }
    explicit operator long double() const {
        return static_cast<long double>(num) / den;
    }
};
template <typename T>
constexpr Rational<T> operator+(const Rational<T>& lhs, const Rational<T>& rhs) { return Rational<T>(lhs) += rhs; }
template <typename T>
constexpr Rational<T> operator-(const Rational<T>& lhs, const Rational<T>& rhs) { return Rational<T>(lhs) -= rhs; }
template <typename T>
constexpr Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs) { return Rational<T>(lhs) *= rhs; }
template <typename T>
constexpr Rational<T> operator/(const Rational<T>& lhs, const Rational<T>& rhs) { return Rational<T>(lhs) /= rhs; }
template <typename T>
constexpr bool operator==(const Rational<T>& lhs, const Rational<T>& rhs) {
    return lhs.numerator() == rhs.numerator() && lhs.denominator() == rhs.denominator();
}
template <typename T>
constexpr bool operator!=(const Rational<T>& lhs, const Rational<T>& rhs) { return !(lhs == rhs); }
template <typename T>
constexpr bool operator<(const Rational<T>& lhs, const Rational<T>& rhs) {
    using int128 = __int128_t;
    return (int128)lhs.numerator() * rhs.denominator() < (int128)rhs.numerator() * lhs.denominator();
}
template <typename T>
constexpr bool operator>(const Rational<T>& lhs, const Rational<T>& rhs) { return rhs < lhs; }
template <typename T>
constexpr bool operator<=(const Rational<T>& lhs, const Rational<T>& rhs) { return !(rhs < lhs); }
template <typename T>
constexpr bool operator>=(const Rational<T>& lhs, const Rational<T>& rhs) { return !(lhs < rhs); }
template <typename T>
std::ostream& operator<<(std::ostream& os, const Rational<T>& r) {
    os << r.numerator();
    if (r.denominator() != 1) {
        os << "/" << r.denominator();
    }
    return os;
}
template <typename T>
std::istream& operator>>(std::istream& is, Rational<T>& r) {
    T n, d = 1;
    is >> n;
    if (is.peek() == '/') {
        is.ignore();
        is >> d;
    }
    r = Rational<T>(n, d);
    return is;
}
#include <initializer_list>
namespace geo {
template <typename T>
Containment contains(const Polygon<T>& poly, const Point<T>& p);
template <typename T>
long double area(const Polygon<T>& poly);
template <typename T>
bool is_convex(const Polygon<T>& poly);
template <typename T> struct Polygon {
public:
    using value_type = Point<T>;
    using reference = value_type&;
    using const_reference = const value_type&;
    using iterator = typename std::vector<Point<T>>::iterator;
    using const_iterator = typename std::vector<Point<T>>::const_iterator;
    using size_type = typename std::vector<Point<T>>::size_type;
    std::vector<Point<T>> vertices;
    Polygon() = default;
    Polygon(size_type n) : vertices(n) {}
    Polygon(std::vector<Point<T>> v) : vertices(std::move(v)) {}
    Polygon(std::initializer_list<Point<T>> il) : vertices(il) {}
    iterator begin() { return vertices.begin(); }
    const_iterator begin() const { return vertices.begin(); }
    iterator end() { return vertices.end(); }
    const_iterator end() const { return vertices.end(); }
    reference operator[](size_type i) { return vertices[i]; }
    const_reference operator[](size_type i) const { return vertices[i]; }
    reference at(size_type i) { return vertices.at(i); }
    const_reference at(size_type i) const { return vertices.at(i); }
    reference front() { return vertices.front(); }
    const_reference front() const { return vertices.front(); }
    reference back() { return vertices.back(); }
    const_reference back() const { return vertices.back(); }
    size_type size() const { return vertices.size(); }
    bool empty() const { return vertices.empty(); }
    void reserve(size_type n) { vertices.reserve(n); }
    void clear() { vertices.clear(); }
    void push_back(const Point<T>& p) { vertices.push_back(p); }
    void pop_back() { vertices.pop_back(); }
    void resize(size_type count) { vertices.resize(count); }
    Containment contains(const Point<T>& p) const { return ::geo::contains(*this, p); }
    auto area() const { return ::geo::area(*this); }
    bool is_convex() const { return ::geo::is_convex(*this); }
};
template <typename T> std::ostream& operator<<(std::ostream& os, const Polygon<T>& poly) { for (size_t i = 0; i < poly.vertices.size(); ++i) { os << poly.vertices[i] << (i == poly.vertices.size() - 1 ? "" : "\n"); } return os; }
template <typename T> std::string debug_format(const Polygon<T>& poly) { std::stringstream ss; ss << "Polygon["; for (size_t i = 0; i < poly.vertices.size(); ++i) { ss << debug_format(poly.vertices[i]) << (i == poly.vertices.size() - 1 ? "" : ", "); } ss << "]"; return ss.str(); }
template <typename T>
long double area(const Polygon<T>& poly) {
    long double a = 0;
    for (size_t i = 0; i < poly.vertices.size(); ++i) {
        a += cross(poly.vertices[i], poly.vertices[(i + 1) % poly.vertices.size()]);
    }
    return std::abs(a / 2.0L);
}
template <typename U>
Rational<U> area(const Polygon<Rational<U>>& poly) {
    Rational<U> a = 0;
    for (size_t i = 0; i < poly.vertices.size(); ++i) {
        a += cross(poly.vertices[i], poly.vertices[(i + 1) % poly.vertices.size()]);
    }
    a /= 2;
    return a < Rational<U>(0) ? -a : a;
}
# 564 "tmp.cpp"
template <typename T>
Containment contains(const Polygon<T>& poly, const Point<T>& p) {
    bool in = false;
    for (size_t i = 0; i < poly.vertices.size(); ++i) {
        Point<T> cur = poly.vertices[i];
        Point<T> next = poly.vertices[(i + 1) % poly.vertices.size()];
        Vector<T> a = cur - p;
        Vector<T> b = next - p;
        if (a.y > b.y) std::swap(a, b);
        if (lt(a.y, (T)0) && ge(b.y, (T)0) && gt(cross(a, b), (T)0)) {
            in = !in;
        }
        if (eq(cross(a, b), (T)0) && le(dot(a, b), (T)0)) {
            return Containment::ON_BOUNDARY;
        }
    }
    return in ? Containment::INSIDE : Containment::OUTSIDE;
}
template<typename T>
bool is_convex(const Polygon<T>& poly) {
    const auto& vertices = poly.vertices;
    int n = vertices.size();
    if (n < 3) return true;
    int turn_dir = 0;
    for (int i = 0; i < n; ++i) {
        auto res = ccw(vertices[i], vertices[(i + 1) % n], vertices[(i + 2) % n]);
        if (res == CCW::COUNTER_CLOCKWISE) {
            if (turn_dir == -1) return false;
            turn_dir = 1;
        } else if (res == CCW::CLOCKWISE) {
            if (turn_dir == 1) return false;
            turn_dir = -1;
        }
    }
    return true;
}
}
using R = Rational<ll>;
using namespace geo;
# 624 "tmp.cpp"
int main() {
    ll g;cin>>g;
    Polygon<R> poly(g);
    rep(i, g) cin >> poly[i];
    ll q;cin>>q;
    rep(i, q){
        Point<R> p;cin>>p;
        auto res = poly.contains(p);
        if(res == Containment::INSIDE) out(2);
        else if(res == Containment::ON_BOUNDARY) out(1);
        else out(0);
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3584
final_rank: 2

code_snippet: #include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#include<iomanip>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<deque>
#include<list>
#include<bitset>
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<ll,ll>;

const ld EPS = 1e-10;
const ll MOD = 1000000007LL;
const ll INF = 1LL << 60;
const ld PI = acos( -1.0 );

#define SWAP( A, B ) { auto tmp = A; A = B; B = tmp; }

template <typename T>
void print( vector<T> v ){
    if( v.size() == 0 ) return;
    for( int i = 0 ; i < v.size() - 1 ; i++ )
        cout << v[i] << ' ';
    cout << v[v.size()-1] << endl;
}

struct Point2d;
using Vector2d = Point2d;
struct Line2d;
struct Segment2d;
struct Triangle2d;
struct Polygon2d;

struct Point2d{

    ld x, y;

    Point2d( ld _x = 0.0, ld _y = 0.0 );

    void normalize();
    void print();

    ld length();
    ld dot( const Vector2d &p );
    ld cross( const Vector2d &p );
    ld distance( Point2d p );
    ld distance( Segment2d s );

    Point2d projection( Line2d l );

    bool on_segment( Segment2d s );

    Point2d operator+( const Point2d &p );
    Point2d operator-( const Point2d &p );
    Point2d operator*( const ld &mul );
    Point2d operator/( const ld &div );
    void operator+=( const Point2d &p );
    void operator-=( const Point2d &p );
    void operator*=( const ld &mul );
    void operator/=( const ld &div );

};

struct Line2d{

    Point2d from, to;

    Line2d( Point2d _from, Point2d _to );

    Vector2d vector();

    Point2d cross_point( Line2d l );

    bool parallel( Line2d l );
    bool orthogonal( Line2d l );

};

struct Segment2d : Line2d{

    Segment2d( Point2d _from, Point2d _to ) : Line2d( _from, _to ){}

    bool intersection( Segment2d s );

    ld distance( Segment2d s );

};

struct Triangle2d{

    vector<Point2d> vertice;

    Triangle2d( vector<Point2d> _vertice );

    ld signed_area();

};

struct Polygon2d{

    int size;
    vector<Point2d> vertice;

    Polygon2d( int _size, vector<Point2d> _vertice );

    bool is_convex();
    bool on_line( Point2d p );

    ld area();

    void contain( Point2d p );

};

istream& operator>>( istream& is, Point2d& dat ){

    return is >> dat.x >> dat.y;

}

ostream& operator<<( ostream& os, const Point2d& dat ){

    return os << fixed << setprecision( 20 ) << dat.x << " " << dat.y;

}

Point2d::Point2d( ld _x, ld _y){

    x = _x;
    y = _y;

}

void Point2d::normalize(){

    ld len = length();
    if( abs( len ) < EPS ) return;
    x /= len;
    y /= len;

}

void Point2d::print(){

    cout << fixed << setprecision( 20 ) << x << " " << y << endl;

}

ld Point2d::length(){

    return sqrt( x * x + y * y );

}

ld Point2d::dot( const Vector2d &p ){

    return x * p.x + y * p.y;

}

ld Point2d::cross( const Vector2d &p ){

    return x * p.y - y * p.x;

}

ld Point2d::distance( Point2d p ){

    Vector2d v( x - p.x, y - p.y );
    return v.length();

}

ld Point2d::distance( Segment2d s ){

    Point2d p = projection( s );
    if( p.on_segment( s ) )
        return distance( p );
    else
        return min( distance( s.from ), distance( s.to ) );

}

Point2d Point2d::projection( Line2d l ){

    Vector2d v1( x - l.from.x, y - l.from.y );
    Vector2d v2 = l.to - l.from;
    v2.normalize();
    return l.from + v2 * v1.dot( v2 );

}

bool Point2d::on_segment( Segment2d s ){

    Vector2d v1( x - s.from.x, y - s.from.y ), v2( x - s.to.x, y - s.to.y );
    return abs( v1.cross( v2 ) ) < EPS && v1.dot( v2 ) < EPS;

}

Point2d Point2d::operator+( const Point2d &p ){

    Point2d res( x + p.x, y + p.y );
    return res;

}

Point2d Point2d::operator-( const Point2d &p ){

    Point2d res( x - p.x, y - p.y );
    return res;

}

Point2d Point2d::operator*( const ld &mul ){

    Point2d res( x * mul, y * mul );
    return res;

}

Point2d Point2d::operator/( const ld &div ){

    Point2d res( x / div, y / div );
    return res;

}

void Point2d::operator+=( const Point2d &p ){

    x += p.x;
    y += p.y;

}

void Point2d::operator-=( const Point2d &p ){

    x -= p.x;
    y -= p.y;

}

void Point2d::operator*=( const ld &mul ){

    x *= mul;
    y *= mul;

}

void Point2d::operator/=( const ld &div ){

    x *= div;
    y *= div;

}

Line2d::Line2d( Point2d _from, Point2d _to ){

    from = _from;
    to = _to;

}

Vector2d Line2d::vector(){

    return Vector2d( to.x - from.x, to.y - from.y );

}

Point2d Line2d::cross_point( Line2d l ){

    if( abs( to.x - from.x ) < EPS ){
        ld katamuki = ( l.to.y - l.from.y ) / ( l.to.x - l.from.x );
        ld seppen = l.to.y - katamuki * l.to.x;
        return Point2d( to.x, katamuki * to.x + seppen );
    }
    else if( abs( l.to.x - l.from.x ) < EPS ){
        ld katamuki = ( to.y - from.y ) / ( to.x - from.x );
        ld seppen = to.y - katamuki * to.x;
        return Point2d( l.to.x, katamuki * l.to.x + seppen );
    }
    else{
        ld katamuki0 = ( to.y - from.y ) / ( to.x - from.x );
        ld seppen0 = to.y - katamuki0 * to.x;
        ld katamuki1 = ( l.to.y - l.from.y ) / ( l.to.x - l.from.x );
        ld seppen1 = l.to.y - katamuki1 * l.to.x;
        return Point2d( ( seppen1 - seppen0 ) / ( katamuki0 - katamuki1 ), ( katamuki0 * seppen1 - katamuki1 * seppen0 ) / ( katamuki0 - katamuki1 ) );
    }

}

bool Line2d::parallel( Line2d l ){

    Vector2d v0 = vector(), v1 = l.vector();
    return abs( v0.cross( v1 ) ) < EPS;

}

bool Line2d::orthogonal( Line2d l ){

    Vector2d v0 = vector(), v1 = l.vector();
    return abs( v0.dot( v1 ) ) < EPS;
    
}

bool Segment2d::intersection( Segment2d s ){

    if( from.on_segment( s ) || to.on_segment( s ) || s.from.on_segment( *this ) || s.to.on_segment( *this ) )
        return true;
    Line2d l0( from, s.from ), l1( from, s.to ), l2( to, s.from ), l3( to, s.to );
    Vector2d v0 = l0.vector(), v1 = l1.vector(), v2 = l2.vector(), v3 = l3.vector();
    return ( v0.cross( v1 ) * v2.cross( v3 ) < -EPS ) && ( v0.cross( v2 ) * v1.cross( v3 ) < -EPS );
}

ld Segment2d::distance( Segment2d s ){

    if( intersection( s ) )
        return 0.0;
    return min( min( from.distance( s ), to.distance( s ) ), min( s.from.distance( *this ), s.to.distance( *this ) ) );

}

Triangle2d::Triangle2d( vector<Point2d> _vertice ){

    vertice = _vertice;

}

ld Triangle2d::signed_area(){

    Vector2d v1( vertice[1].x - vertice[0].x, vertice[1].y - vertice[0].y );
    Vector2d v2( vertice[2].x - vertice[0].x, vertice[2].y - vertice[0].y );
    return v1.cross( v2 ) / 2.0;

}

Polygon2d::Polygon2d( int _size, vector<Point2d> _vertice ){

    size = _size;
    vertice = _vertice;

}

bool Polygon2d::is_convex(){

    vector<Vector2d> edges;
    for( int i = 0 ; i < size ; i++ ){
        Vector2d edge( vertice[(i+1)%size].x - vertice[i].x, vertice[(i+1)%size].y - vertice[i].y );
        edges.push_back( edge );
    }
    for( int i = 0 ; i < size - 1 ; i++ ){
        if( edges[i].cross( edges[i+1] ) < -EPS )
            return false;
    }
    return true;

}

bool Polygon2d::on_line( Point2d p ){

    vector<Segment2d> edges;
    for( int i = 0 ; i < size ; i++ ){
        Segment2d edge( vertice[i], vertice[(i+1)%size] );
        edges.push_back( edge );
    }
    for( int i = 0 ; i < size ; i++ ){
        if( p.on_segment( edges[i] ) )
            return true;
    }
    return false;

}

ld Polygon2d::area(){

    ld res = 0.0;
    for( int i = 1 ; i < size - 1 ; i++ ){
        vector<Point2d> v;
        v.push_back( vertice[0] );
        v.push_back( vertice[i] );
        v.push_back( vertice[i+1] );
        Triangle2d t( v );
        res += t.signed_area();
    }
    return res;

}

void Polygon2d::contain( Point2d p ){

    if( on_line( p ) ){
        cout << 1 << endl;
        return;
    }
    ld angle = 0.0;
    for( int i = 0 ; i < size ; i++ ){
        Vector2d v1( vertice[i].x - p.x, vertice[i].y - p.y );
        v1.normalize();
        Vector2d v2( vertice[(i+1)%size].x - p.x, vertice[(i+1)%size].y - p.y );
        v2.normalize();
        if( v1.cross( v2 ) > EPS )
            angle += acos( v1.dot( v2 ) );
        else if( v1.cross( v2 ) < -EPS )
            angle -= acos( v1.dot( v2 ) );
    }
    if( angle < EPS )
        cout << 0 << endl;
    else
        cout << 2 << endl;

}

void counter_clockwise( const Point2d &p0, const Point2d &p1, const Point2d &p2 ){

    Line2d l1( p0, p1 ), l2( p0, p2 );
    Vector2d v1 = l1.vector(), v2 = l2.vector();
    ld c = v1.cross( v2 );
    if( c > EPS )
        cout << "COUNTER_CLOCKWISE" << endl;
    else if( c < -EPS )
        cout << "CLOCKWISE" << endl;
    else{
        ld d = v1.dot( v2 );
        if( d > -EPS ){
            if( v1.length() < v2.length() )
                cout << "ONLINE_FRONT" << endl;
            else
                cout << "ON_SEGMENT" << endl;
        }
        else
            cout << "ONLINE_BACK" << endl;
    }

}

int main(){

    int n, q;
    Point2d tmp;
    vector<Point2d> v;

    cin >> n;
    for( int i = 0 ; i < n ; i++ ){
        cin >> tmp;
        v.push_back( tmp );
    }
    Polygon2d p( n, v );
    cin >> q;
    for( int i = 0 ; i < q ; i++ ){
        cin >> tmp;
        p.contain( tmp );
    }

}
accuracy: 1
time_ms: 10
memory_kb: 3588
final_rank: 3

code_snippet: // #define _GLIBCXX_DEBUG
#define EPSILON (1e-10)
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
ll MOD = 998244353;
// ==================copyここから=======================

enum class CCW
{
  COUNTER_CLOCKWISE, // 反時計周り
  CLOCKWISE,         // 時計回りの位置
  ONLINE_BACK,       // 逆向き延長線上
  ONLINE_FRONT,      // 正向き延長線上
  ON_SEGMENT,        // ベクトル上
};

/**
 * =======================
 * N次元ベクトルクラスVector
 * =======================
 */
struct Vector
{
  ll dim;

private:
  vector<double> coord;

public:
  Vector(ll n = 2)
  {
    this->coord = vector<double>(n, 0);
    this->dim = n;
  }
  Vector(vector<double> coord)
  {
    this->coord = coord;
    this->dim = coord.size();
  }

  double norm(double p = 2) const
  {
    double ret = 0;
    for (auto e : this->coord)
    {
      ret += pow(e, p);
    }
    return pow(ret, 1 / p);
  }

  Vector unit() const
  {
    vector<double> v(this->coord.size());
    for (ll i = 0; i < this->dim; i++)
    {
      v[i] = this->coord[i] / this->norm(2);
    }
    return Vector(v);
  }

  Vector normal_unit2D() const
  {
    if (this->dim != 2)
    {
      throw runtime_error("DimensionMustBe2");
    }
    vector<double> v(this->coord.size());
    v[0] = -this->coord[1];
    v[1] = this->coord[0];
    return Vector(v).unit();
  }

  double operator*(const Vector &v) const
  {
    if (this->coord.size() != v.coord.size())
    {
      throw runtime_error("MismatchOfVectorSizeError");
    }
    double inner_product = 0;
    rep(i, this->coord.size())
    {
      inner_product += this->coord[i] * v.coord[i];
    }
    return inner_product;
  }

  double cross2D(const Vector &v) const
  {
    ll DIM = 2;
    if (v.dim != DIM || this->dim != DIM)
    {
      throw runtime_error("Not2DimensionVector");
    }
    return this->coord[0] * v.coord[1] - this->coord[1] * v.coord[0];
  }

  Vector cross3D(const Vector &v) const
  {
    ll DIM = 3;
    if (v.dim != DIM || this->dim != DIM)
    {
      throw runtime_error("Not3DimensionVector");
    }
    return Vector(vector<double>{
        this->coord[1] * v.coord[2] - this->coord[2] * v.coord[1],
        this->coord[2] * v.coord[0] - this->coord[0] * v.coord[2],
        this->coord[0] * v.coord[1] - this->coord[1] * v.coord[0],
    });
  }
  void print(bool no_line = false) const
  {
    cout << "(";
    rep(i, this->dim)
    {
      cout << this->coord[i]
           << (i != this->dim - 1 ? ", " : ")");
    }
    if (!no_line)
    {
      cout << endl;
    }
  }

  /**
   * 位置関係判定メソッド
   */
  enum CCW ccw(const Vector &v) const
  {
    if (this->dim != 2 || v.dim != 2)
    {
      throw runtime_error("Not2DimensionVector");
    }
    auto cross = this->cross2D(v);
    if (cross > 0)
    {
      return CCW::COUNTER_CLOCKWISE;
    }
    if (cross < 0)
    {
      return CCW::CLOCKWISE;
    }
    if ((*this) * v < 0)
    {
      return CCW::ONLINE_BACK;
    }
    if (this->norm() < v.norm())
    {
      return CCW::ONLINE_FRONT;
    }
    return CCW::ON_SEGMENT;
  }

  Vector operator+(const Vector &v) const
  {
    if (this->coord.size() != v.coord.size())
    {
      throw runtime_error("MismatchOfVectorSizeError");
    }
    vector<double> sum_v;
    rep(i, v.coord.size())
    {
      sum_v.push_back(this->coord[i] + v.coord[i]);
    }
    return Vector(sum_v);
  }

  Vector operator-(const Vector &v) const
  {
    if (this->coord.size() != v.coord.size())
    {
      throw runtime_error("MismatchOfVectorSizeError");
    }
    vector<double> sum_v;
    rep(i, v.coord.size())
    {
      sum_v.push_back(this->coord[i] - v.coord[i]);
    }
    return Vector(sum_v);
  }

  double operator[](size_t t)
  {
    return this->coord.at(t);
  }
  double operator[](size_t t) const
  {
    return this->coord.at(t);
  }

  bool operator==(const Vector &v) const
  {
    if (this->coord.size() != v.coord.size())
    {
      return false;
    }
    rep(i, this->coord.size())
    {
      if (EPSILON < abs(this->coord[i] - v.coord[i]))
      {
        return false;
      }
    }
    return true;
  }
};

Vector operator*(const Vector left_v, const double k)
{
  vector<double> kv(left_v.dim);
  rep(i, left_v.dim)
  {
    kv[i] = k * left_v[i];
  }
  return Vector(kv);
}

Vector operator*(const double k, const Vector left_v)
{
  vector<double> kv(left_v.dim);
  rep(i, left_v.dim)
  {
    kv[i] = k * left_v[i];
  }
  return Vector(kv);
}

bool operator<(const Vector &left_v, const Vector &right_v)
{
  if (left_v.dim != right_v.dim)
  {
    throw runtime_error("MustBeSameDimension");
  }
  rep(i, left_v.dim)
  {
    if (abs(left_v[i] - right_v[i]) < EPSILON)
    {
      continue;
    }
    return left_v[i] < right_v[i];
  }
  return true;
}

bool operator>(const Vector &left_v, const Vector &right_v)
{
  return !(left_v < right_v);
}

bool operator<=(const Vector &left_v, const Vector &right_v)
{
  if (left_v.dim != right_v.dim)
  {
    throw runtime_error("MustBeSameDimension");
  }
  rep(i, left_v.dim)
  {
    if (abs(left_v[i] - right_v[i]) < EPSILON)
    {
      continue;
    }
    return left_v[i] <= right_v[i];
  }
  return true;
}

bool operator>=(const Vector &left_v, const Vector &right_v)
{
  if (left_v.dim != right_v.dim)
  {
    throw runtime_error("MustBeSameDimension");
  }
  rep(i, left_v.dim)
  {
    if (abs(left_v[i] - right_v[i]) < EPSILON)
    {
      continue;
    }
    return left_v[i] >= right_v[i];
  }
  return true;
}

/**
 * ==================
 * N次元直線クラスLine
 * ==================
 */
struct Line
{
  Vector v1, v2;
  Line(const vector<double> &v1, const vector<double> &v2) : v1(v1), v2(v2)
  {
    if (this->v1 == this->v2)
    {
      throw runtime_error("ShouldBeDefferentPoint");
    }
    if (this->v1.dim != this->v2.dim)
    {
      throw runtime_error("ShouldBeInSameDimension");
    }
  }

  Line(const Vector &v1, const Vector &v2)
  {
    if (v1 == v2)
    {
      throw runtime_error("ShouldBeDefferentPoint");
    }
    if (v1.dim != v2.dim)
    {
      throw runtime_error("ShouldBeInSameDimension");
    }
    this->v1 = v1;
    this->v2 = v2;
  }
  /**
   * 平行判定メソッド
   */
  bool is_horizontal(const Line &l) const
  {
    auto direction1 = this->v1 - this->v2;
    auto direction2 = l.v1 - l.v2;
    if (direction1.dim != direction2.dim)
    {
      throw runtime_error("ShouldBeInSameDimension");
    }
    return abs(abs(direction1.norm(2) * direction2.norm(2)) - abs(direction1 * direction2)) < EPSILON;
  }
  /**
   * 垂直判定メソッド
   */
  bool is_orthogonal(const Line &l) const
  {
    auto direction1 = this->v1 - this->v2;
    auto direction2 = l.v1 - l.v2;
    if (direction1.dim != direction2.dim)
    {
      throw runtime_error("ShouldBeInSameDimension");
    }
    return abs(direction1 * direction2) < EPSILON;
  }
  /**
   * 交点計算メソッド
   */
  // Vector intersecting_point(Line l) {}

  /**
   * 点との距離計算メソッド
   */
  double distance2D(const Vector &p) const
  {
    if (this->v1.dim != 2 || this->v2.dim != 2 || p.dim != 2)
    {
      throw runtime_error("DimensionMustBe2");
    }
    auto v1 = p - this->v1;
    auto v2 = this->v2 - this->v1;
    auto pj_len = v2.unit() * v1; // 射影ベクトルの長さ(逆向きの場合は負)
    return (pj_len * v2.unit() - v1).norm(2);
  }

  Vector dirction_unit_vector() const
  {
    return (this->v1 - this->v2).unit();
  }

  bool is_online(const Vector &p) const
  {
    return this->distance2D(p) < EPSILON;
  }
};

/**
 * =====================
 * N次元線分クラスSegment
 * =====================
 */
struct Segment : public Line
{
  using Line::Line;
  void print() const
  {
    this->v1.print(true);
    cout << ", ";
    this->v1.print();
  }
  double len() const
  {
    return (this->v1 - this->v2).norm(2);
  }
  bool is_intersected2D(const Segment &s) const
  {
    if (this->v1.dim != 2 || this->v2.dim != 2 || s.v1.dim != 2 || s.v2.dim != 2)
    {
      throw runtime_error("DimensionMustBe2");
    }
    auto a1 = this->v2 - this->v1;
    auto a2 = s.v1 - this->v1;
    auto a3 = s.v2 - this->v1;
    auto ccw11 = a1.ccw(a2);
    auto ccw12 = a1.ccw(a3);
    if (ccw11 == CCW::ON_SEGMENT || ccw12 == CCW::ON_SEGMENT)
    {
      return true;
    }
    if (
        (ccw11 == CCW::COUNTER_CLOCKWISE && ccw12 == CCW::CLOCKWISE) ||
        (ccw11 == CCW::CLOCKWISE && ccw12 == CCW::COUNTER_CLOCKWISE))
    {
    }
    else if (
        (ccw11 == CCW::ONLINE_BACK && ccw12 == CCW::ONLINE_FRONT) ||
        (ccw11 == CCW::ONLINE_FRONT && ccw12 == CCW::ONLINE_BACK))
    {
      return true;
    }
    else
    {
      return false;
    }

    auto b1 = s.v2 - s.v1;
    auto b2 = this->v1 - s.v1;
    auto b3 = this->v2 - s.v1;
    auto ccw21 = b1.ccw(b2);
    auto ccw22 = b1.ccw(b3);
    if (ccw21 == CCW::ON_SEGMENT || ccw22 == CCW::ON_SEGMENT)
    {
      return true;
    }
    if (
        (ccw21 == CCW::COUNTER_CLOCKWISE && ccw22 == CCW::CLOCKWISE) ||
        (ccw21 == CCW::CLOCKWISE && ccw22 == CCW::COUNTER_CLOCKWISE))
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  double distance2D(const Vector &p) const
  {
    if (this->v1.dim != 2 || this->v2.dim != 2 || p.dim != 2)
    {
      throw runtime_error("DimensionMustBe2");
    }
    auto v1 = p - this->v1;
    auto v2 = this->v2 - this->v1;
    auto pj_len = v2.unit() * v1; // 射影ベクトルの長さ(逆向きの場合は負)
    if (v2.norm(2) <= pj_len || pj_len <= 0)
    {
      return min((p - this->v1).norm(2), (p - this->v2).norm(2));
    }
    else
    {
      return (pj_len * v2.unit() - v1).norm(2);
    }
  }
  double distance2D(const Segment &s) const
  {
    if (this->is_intersected2D(s))
    {
      return 0;
    }
    return min(
        min(this->distance2D(s.v1), this->distance2D(s.v2)),
        min(s.distance2D(this->v1), s.distance2D(this->v2)));
  }

  Vector intersection_point2D(Segment s)
  {
    if (!this->is_intersected2D(s))
    {
      throw runtime_error("NotIntersected");
    }
    Line l(this->v1, this->v2);
    auto t = (l.distance2D(s.v1)) / (l.distance2D(s.v1) + l.distance2D(s.v2));
    return s.v1 + (s.v2 - s.v1) * t;
  }

  bool is_online(const Vector &p) const
  {
    return this->distance2D(p) < EPSILON;
  }
};

struct Circle
{
  Vector center;
  double radius;
  Circle(vector<double> center, double radius) : center(center),
                                                 radius(radius)
  {
  }

  vector<Vector> intersection_point2D(const Line &l) const
  {
    auto d = l.distance2D(this->center);
    auto a1 = this->center + (l.v1 - l.v2).normal_unit2D() * d;
    auto a2 = this->center - (l.v1 - l.v2).normal_unit2D() * d;
    Vector a;
    if (l.is_online(a1))
    {
      a = a1;
    }
    else
    {
      a = a2;
    }
    vector<Vector> intersection_points;
    if (abs(d - this->radius) < EPSILON)
    {
      intersection_points.push_back(a);
    }
    else
    {
      auto length = pow(pow(this->radius, 2) - pow(d, 2), 0.5);
      intersection_points.push_back(a + length * l.dirction_unit_vector());
      intersection_points.push_back(a - length * l.dirction_unit_vector());
    }
    sort(intersection_points.begin(), intersection_points.end());
    return intersection_points;
  }

  vector<Vector> intersection_point2D(const Circle &c) const
  {
    vector<Vector> intersection_points;
    auto c1c2 = c.center - this->center;
    auto d = c1c2.norm(2);
    if (this->radius + c.radius < d)
    {
      return intersection_points;
    }
    auto d1 = (pow(d, 2) + pow(this->radius, 2) - pow(c.radius, 2)) / (2 * d);
    auto m = this->center + c1c2.unit() * d1;
    auto h = pow(pow(this->radius, 2) - pow(d1, 2), 0.5);
    if (abs(this->radius + c.radius - d) < EPSILON)
    {
      intersection_points.push_back(this->center + c1c2.unit() * d1);
    }
    else
    {
      intersection_points.push_back(this->center + c1c2.unit() * d1 + c1c2.normal_unit2D() * h);
      intersection_points.push_back(this->center + c1c2.unit() * d1 - c1c2.normal_unit2D() * h);
    }

    sort(intersection_points.begin(), intersection_points.end());
    return intersection_points;
  }

  double area() const
  {
    return M_PI * this->radius * this->radius;
  }
};

enum class POLYGON2D_INCLUSION_STATUS
{
  INCLUDED,
  ON_BOUNDARY,
  EXCLUDED,
};

struct Polygon2D
{
  vector<Vector> points;
  Polygon2D(const vector<vector<double>> &points)
  {
    for (auto p : points)
    {
      this->points.push_back(Vector(p));
    }
  }
  enum POLYGON2D_INCLUSION_STATUS get_inclusion_status(const Vector &v) const
  {
    bool flag = false;
    rep(i, this->points.size())
    {
      auto v1 = this->points[i];
      Vector v2;
      if (i == this->points.size() - 1)
      {
        v2 = this->points[0];
      }
      else
      {
        v2 = this->points[i + 1];
      }
      if (v2[1] < v1[1])
      {
        auto tmp = v1;
        v1 = v2;
        v2 = tmp;
      }
      Segment s(v1, v2);
      if (s.is_online(v))
      {
        return POLYGON2D_INCLUSION_STATUS::ON_BOUNDARY;
      }
      if (v2[1] <= v[1] || v[1] < v1[1])
      {
        continue;
      }
      auto cross = (v - v1).cross2D(v - v2);
      if (0 < cross)
      {
        flag = !flag;
      }
    }
    if (flag)
    {
      return POLYGON2D_INCLUSION_STATUS::INCLUDED;
    }
    else
    {
      return POLYGON2D_INCLUSION_STATUS::EXCLUDED;
    }
  }
};

// ==================copyここまで=======================

int main()
{
  // input
  ll n;
  double x, y;
  vector<vector<double>> poly;
  vector<vector<double>> points;
  cin >> n;
  rep(i, n)
  {
    cin >> x >> y;
    poly.push_back(vector<double>{x, y});
  }
  cin >> n;
  rep(i, n)
  {
    cin >> x >> y;
    points.push_back(vector<double>{x, y});
  }

  // solve
  Polygon2D polygon(poly);
  vector<int> answers;
  rep(i, n)
  {
    auto ans = polygon.get_inclusion_status(Vector(points[i]));
    switch (ans)
    {
    case POLYGON2D_INCLUSION_STATUS::INCLUDED:
      answers.push_back(2);
      break;
    case POLYGON2D_INCLUSION_STATUS::EXCLUDED:
      answers.push_back(0);
      break;
    case POLYGON2D_INCLUSION_STATUS::ON_BOUNDARY:
      answers.push_back(1);
      break;
    }
  }

  // output
  for (auto a : answers)
  {
    cout << a << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 4020
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ld = long double;
const ld eps = 1e-6;
int sign(ld x) { return fabs(x) < eps ? 0 : x < 0 ? -1 : 1; }
using vec = complex<ld>;
#define x(z) real(z)
#define y(z) imag(z)
istream& operator >>(istream &in, vec &p) { ld x, y; cin >> x >> y; p = {x, y}; return in; }
#define C(a, b) y(conj(a) * (b))
bool onseg(vec a, vec p, vec q) { return !sign(C(q - p, a - p)) && x(a) > min(x(p), x(q)) - eps && x(a) < max(x(p), x(q)) + eps && y(a) > min(y(p), y(q)) - eps && y(a) < max(y(p), y(q)) + eps; }
vec intersection(vec a, vec b, vec c, vec d) {
	return a + (b - a) * (C(a - c, d - c) / C(d - c, b - a));
}
bool hasinter(vec a, vec b, vec c, vec d) {
	vec o = intersection(a, b, c, d);
	return onseg(o, a, b) && onseg(o, c, d);
}
int inPoly(vec p, vector<vec> a) {
	static mt19937 eng(chrono::steady_clock::now().time_since_epoch().count());
	static uniform_real_distribution<ld> uni(1e5, 2e5);
	vec q(uni(eng), uni(eng));
	int cnt = 0;
	for (int i = 0; i < a.size(); i++) {
		if (onseg(p, a[i], a[(i + 1) % a.size()])) return 0;
		cnt += hasinter(a[i], a[(i + 1) % a.size()], p, q);
	}
	return cnt % 2 ? 1 : -1;
}
int main() {
	cin.tie(0)->sync_with_stdio(0);
	int n;
	cin >> n;
	vector<vec> g(n);
	for (auto &i : g) {
		cin >> i;
	}
	int q;
	cin >> q;
	while (q--) {
		vec o;
		cin >> o;
		cout << inPoly(o, g) + 1 << "\n";
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3532
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define pii pair<int, int>
#define mp make_pair
#define fi first
#define se second
#define deb(var) cerr << #var << '=' << (var) << "; "
#define double long double
const double eps = 1e-8, inf = 1e20, pi = acos(-1.0);
int sgn(double x) {
	return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1); 
} 
double sqr(double x) { return x * x; }
struct Point {
	double x, y;
	Point() { x = y = 0; }
	Point(double a, double b) { x = a, y = b; }
	void input() { cin >> x >> y; }
	void output(int k) const { cout << fixed << setprecision(k) << x << ' ' << y << '\n'; }
	bool operator == (Point b) const { return sgn(x - b.x) == 0 && sgn(y - b.y) == 0; }
	bool operator < (Point b) const { return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x; }
	Point operator + (Point b) const { return Point(x + b.x, y + b.y); }
	Point operator - (Point b) const { return Point(x - b.x, y - b.y); } 
	Point operator * (double k) const { return Point(x * k, y * k); }
	Point operator / (double k) const { return Point(x / k, y / k); }
	double operator * (Point b) const { return x * b.x + y * b.y; }   // 向量点积
	double operator ^ (Point b) const { return x * b.y - y * b.x; }   // 向量叉积 
	friend double dis(Point a, Point b) { return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)); }   // 两点距离 
	friend double dis(Point a) { return dis(Point(), a); }
	friend Point unit(Point a) { return Point() == a ? a : a / dis(a); }   // 向量单位化
	friend Point turn(Point a, double k) { return Point(a.x * cos(k) - a.y * sin(k), a.y * cos(k) + a.x * sin(k)); }   // 逆时针旋转弧度 k
	friend Point move(Point a, Point b) { return a + b; }   // 移动向量 b 
	friend double angle(Point a, Point b) { return sgn(a ^ b) * acos(a * b / dis(a) / dis(b)); }   // a 到 b 的夹角
};
struct Line {
	Point s, t;
	Line() { s = t = Point(); };
	Line(Point a, Point b) { s = a, t = b; }
	void input() { s.input(), t.input(); }
	bool operator == (Line b) const { return s == b.s && t == b.t; }
	friend double len(Line a) { return dis(a.s, a.t); }
	friend Point prog(Point a, Line b) {   // 点到直线投影 
		a = a - b.s, b.t = b.t - b.s;
		return b.s + unit(b.t) * (a * b.t / dis(b.t));
	}
	friend double dis(Point a, Line b) { return dis(a, prog(a, b)); }   // 点到直线距离
	friend Point symm(Point a, Line b) { return prog(a, b) * 2 - a; }   // 点关于直线的对称点
	friend Line turn(Line a, double k) { return Line(turn(a.s, k), turn(a.t, k)); }
	friend Line move(Line a, Point b) { return Line(move(a.s, b), move(a.t, b)); }
	friend bool online(Line a, Point b) { return sgn((a.t - a.s) ^ (b - a.s)) == 0; }   // 点在直线上 
	friend bool onsegm(Line a, Point b) {   // 点在线段上 
		return online(a, b) && sgn((b - a.s) * (b - a.t)) <= 0;
	}
	friend int rela(Line a, Line b) {   // 两直线关系  共线 1；平行 2；相交 3 
		Point del = Point() - a.s; a = move(a, del), b = move(b, del);
		double k = angle(a.t, Point(1, 0)); a = turn(a, k), b = turn(b, k);
		if (sgn(b.s.y) == 0 && sgn(b.t.y) == 0) return 1;
		if (sgn(b.s.y - b.t.y) == 0) return 2; return 3;
	} 
	friend Point sect(Line a, Line b) {   // 直线交点 
		Point del = Point() - a.s; a = move(a, del), b = move(b, del);
		double k = angle(a.t, Point(1, 0)); a = turn(a, k), b = turn(b, k);
		double t = -(b.t.x - b.s.x) * b.s.y, d = b.t.y - b.s.y; 
		Point ans = Point(t / d + b.s.x, 0); ans = move(turn(ans, -k), Point() - del); return ans;
	}
	friend int rela_segline(Line a, Line b) {   // 线段 a 和直线 b 的关系  相交：1；无交：0
		return sgn((b.t - b.s) ^ (a.s - b.s)) * sgn((b.t - b.s) ^ (a.t - b.s)) <= 0;
	}
	friend int rela_segseg(Line a, Line b) {   // 线段 a 和线段 b 的关系  相交：1；无交：0
		if (rela(a, b) == 1) return onsegm(b, a.t) | onsegm(b, a.s) | onsegm(a, b.s);
		Point p = sect(a, b);
		return onsegm(a, p) && onsegm(b, p); 
	} 
	friend Point sect_segseg(Line a, Line b) {   // 线段 a，b 的交点 
		if (rela(a, b) == 1) return onsegm(b, a.t) ? a.t : onsegm(b, a.s) ? a.s : b.s; return sect(a, b); 
	}
	friend double dis_seg(Point a, Line b) {   // 点到线段距离 
		if (onsegm(b, prog(a, b))) return dis(a, b); else return min(dis(a, b.s), dis(a, b.t));
	}
	friend double dis_segseg(Line a, Line b) {   // 线段 a，b 的距离
	    if (rela_segseg(a, b)) return 0;
		double ans = inf; 
		ans = min(ans, dis_seg(b.s, a));
		ans = min(ans, dis_seg(b.t, a));
		ans = min(ans, dis_seg(a.s, b));
		ans = min(ans, dis_seg(a.t, b)); return ans; 
	}
};
struct Polygon {
	vector<Point> p;
	Polygon() { p.clear(); }
	Polygon(vector<Point> q) { p = q; }
	void input(int n) {
		p.clear(); Point q; while (n--) q.input(), p.push_back(q);
	}
	void output(int k) {
		for (int i = 0; i < p.size(); i++) p[i].output(k); 
	}
	const int size() const { return p.size(); }
	void pop_back() { p.pop_back(); }
	void push_back(Point x) { p.pb(x); }
	Point& operator [](int k) { return p[k]; }
	vector<Point>::iterator begin() { return p.begin(); }
	vector<Point>::iterator end() { return p.end(); } 
	friend int rela(Polygon p, Point v) {   // 0 v 在 g 外；1 v 在 g 上；2 v 在 g 内 
		int cnt = 0;
		for (int i = 0; i < p.size(); i++) {
			Point s = p[i] - v, t = p[(i + 1) % (int)p.size()] - v; Line l = Line(s, t);
			if (onsegm(l, Point())) return 1;
			if (s.y > t.y) swap(s, t);
			int b = sgn(s.y) * sgn(t.y) <= 0 && sgn(t.y) != 0;
			Point sct = sect(l, Line(Point(), Point(1, 0)));
			cnt += b && sgn(sct.y) == 0 && sgn(sct.x) >= 0;
		} return cnt % 2 ? 2 : 0;
	}
	struct angle_cmp {
		Point p;
		angle_cmp() {}
		angle_cmp(Point x) { p = x; } 
		bool operator ()(Point a, Point b) const {
			a = a - p, b = b - p;
			return sgn(atan2(a.y, a.x) - atan2(b.y, b.x)) == 0 ? dis(a) < dis(b) : atan2(a.y, a.x) < atan2(b.y, b.x);
		}
	};
	friend bool isconvex(Polygon p) {
		bool bk[3] = {0, 0, 0};
		for (int i = 0; i < p.size(); i++) {
			int j = (i + 1) % (int)p.size(), k = (j + 1) % (int)p.size();
			bk[sgn((p[j] - p[i]) ^ (p[k] - p[j])) + 1] = 1; if ((bk[0] && bk[2]) || bk[1]) return 0;
		}
		return 1;
	} 
	friend Polygon getconvex(Polygon p) {   // 求凸包（逆时针） 
		if (p.size() <= 1) return p;
		for (int i = 1; i < p.size(); i++)
			if (p[i].y < p[0].y) swap(p[i], p[0]);
		sort(p.begin() + 1, p.end(), angle_cmp(p[0]));
		vector<Point> st(0); st.pb(p[0]); int top = 0;
		for (int i = 1; i < p.size(); i++) {
			while (top > 0 && sgn((st[top] - st[top - 1]) ^ (p[i] - st[top - 1])) <= 0) top--, st.pop_back(); st.push_back(p[i]); top++;
		}
		return Polygon(st);
	}
	double peri() const {   // 周长 
		double ans = 0; for (int i = 0; i < p.size(); i++) ans += dis(p[i], p[(i + 1) % (int)p.size()]); return ans;
	}
	double area() const {   // 面积 
		double ans = 0; for (int i = 0; i < p.size(); i++) ans += p[i] ^ p[(i + 1) % (int)p.size()]; return fabs(ans) / 2;
	}
	double diam() const {   // 直径（逆时针） 
		int n = p.size();
		double ans = 0;
		for (int i = 0, k = 0; i < p.size(); i++) {
			while (sgn(dis(p[i], Line(p[(k + 1) % n], p[(k + 2) % n])) - dis(p[i], Line(p[k], p[(k + 1) % n]))) > 0) k = (k + 1) % n; ans = max(ans, max(dis(p[i], p[k]), dis(p[i], p[(k + 1) % n]))); 
		}
		return ans;
	}
//	friend Polygon minkow(Polygon a, Polygon b) {   // 闵可夫斯基和 
//		
//	}
}; 
Polygon g;
signed main() {
	int n; cin >> n; g.input(n); int q; cin >> q;
	while (q--) {
		Point p; p.input(); cout << rela(g, p) << "\n";
	}
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3576
final_rank: 4