#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
struct Mesh {
static const int MAXN = 1e5 + 5;
int pt[MAXN][2];
vector<int> X;
void read(int n) {
for (int i = 0; i < n; i++)
scanf("%d %d", &pt[i][0], &pt[i][1]);
X.clear(); X.reserve(n);
for (int i = 0; i < n; i++)
X.push_back(pt[i][0]);
sort(X.begin(), X.end());
X.erase(unique(X.begin(), X.end()), X.end());
}
} mesh;
class SplayTree {
public:
struct Node {
Node *ch[2], *fa;
int size; int data;
Node() {
ch[0] = ch[1] = fa = NULL;
size = 1;
}
bool is_root() {
return fa->ch[0] != this && fa->ch[1] != this;
}
};
Node *root, *EMPTY;
void pushdown(Node *u) {}
void pushup(Node *u) {
if (u->ch[0] != EMPTY) pushdown(u->ch[0]);
if (u->ch[1] != EMPTY) pushdown(u->ch[1]);
u->size = 1 + u->ch[0]->size + u->ch[1]->size;
}
void setch(Node *p, Node *u, int i) {
if (p != EMPTY) p->ch[i] = u;
if (u != EMPTY) u->fa = p;
}
SplayTree() {
EMPTY = new Node();
EMPTY->fa = EMPTY->ch[0] = EMPTY->ch[1] = EMPTY;
EMPTY->size = 0;
}
void init() {
root = EMPTY;
}
Node* newNode() {
Node *u = new Node();
u->fa = u->ch[0] = u->ch[1] = EMPTY;
return u;
}
void rotate(Node *x) {
Node *y;
int d;
y = x->fa, d = y->ch[1] == x ? 1 : 0;
x->ch[d^1]->fa = y, y->ch[d] = x->ch[d^1];
x->ch[d^1] = y;
if (!y->is_root())
y->fa->ch[y->fa->ch[1] == y] = x;
x->fa = y->fa, y->fa = x;
pushup(y);
}
void deal(Node *x) {
if (!x->is_root()) deal(x->fa);
pushdown(x);
}
void splay(Node *x, Node *below) {
if (x == EMPTY) return ;
Node *y, *z;
deal(x);
while (!x->is_root() && x->fa != below) {
y = x->fa, z = y->fa;
if (!y->is_root() && y->fa != below) {
if (y->ch[0] == x ^ z->ch[0] == y)
rotate(x);
else
rotate(y);
}
rotate(x);
}
pushup(x);
if (x->fa == EMPTY) root = x;
}
Node* prevNode(Node *u) {
splay(u, EMPTY);
return maxNode(u->ch[0]);
}
Node* nextNode(Node *u) {
splay(u, EMPTY);
return minNode(u->ch[1]);
}
Node* minNode(Node *u) {
Node *p = u->fa;
for (; pushdown(u), u->ch[0] != EMPTY; u = u->ch[0]);
splay(u, p);
return u;
}
Node* maxNode(Node *u) {
Node *p = u->fa;
for (; pushdown(u), u->ch[1] != EMPTY; u = u->ch[1]);
splay(u, p);
return u;
}
Node* findPos(int pos) {
for (Node *u = root; u != EMPTY;) {
pushdown(u);
int t = u->ch[0]->size;
if (t == pos) {
splay(u, EMPTY);
return u;
}
if (t > pos)
u = u->ch[0];
else
u = u->ch[1], pos -= t + 1;
}
return EMPTY;
}
tuple<int, int, int> insert(int data, int pos) {
Node *p, *q = findPos(pos);
Node *x = newNode(); x->data = data;
if (q == EMPTY) {
p = maxNode(root), splay(p, EMPTY);
setch(x, p, 0);
splay(x, EMPTY);
} else {
splay(q, EMPTY), p = q->ch[0];
setch(x, p, 0), setch(x, q, 1);
setch(q, EMPTY, 0);
splay(q, EMPTY);
p = prevNode(x);
}
if (p == EMPTY) p = maxNode(root);
if (q == EMPTY) q = minNode(root);
return make_tuple(p->data, data, q->data);
}
tuple<int, int, int> remove(int pos) {
Node *x = findPos(pos), *p, *q;
p = prevNode(x), q = nextNode(x);
if (p != EMPTY && q != EMPTY) {
setch(p, q, 1);
p->fa = EMPTY, splay(q, EMPTY);
} else if (p != EMPTY) {
p->fa = EMPTY, root = p;
} else {
q->fa = EMPTY, root = q;
}
int del = x->data;
delete x;
if (p == EMPTY) p = maxNode(root);
if (q == EMPTY) q = minNode(root);
return make_tuple(p->data, del, q->data);
}
int size() {
return root == EMPTY ? 0 : root->size;
}
} mlist;
struct Pt {
double x, y;
Pt() {}
Pt(int xy[]):Pt(xy[0], xy[1]) {}
Pt(double x, double y):x(x), y(y) {}
bool operator<(const Pt &o) const {
if (x != o.x) return x < o.x;
return y < o.y;
}
};
struct PtP {
static double x;
Pt p, q;
PtP(Pt a, Pt b) {
p = a, q = b;
if (q < p)
swap(p, q);
}
double interpolate(const Pt& p1, const Pt& p2, double& x) const {
if (p1.x == p2.x) return min(p1.y, p2.y);
return p1.y + (p2.y - p1.y) / (p2.x - p1.x) * (x - p1.x);
}
bool operator<(const PtP &o) const {
return interpolate(p, q, x) < interpolate(o.p, o.q, x);
}
};
double PtP::x = 1;
struct SegSeg {
struct Node {
Node *lson, *rson;
tree<pair<PtP, int>, null_type, less<pair<PtP, int>>, rb_tree_tag, tree_order_statistics_node_update> segs;
Node() {
lson = rson = NULL;
}
};
Node *root;
int xn;
Node* newNode() {
return new Node();
}
void freeNode(Node *u) {
free(u);
}
void init() {
root = NULL;
xn = mesh.X.size();
}
void insert(tuple<int, int, int> e) {
int p, q, r; tie(p, q, r) = e;
remove(0, xn-1, {PtP(Pt(mesh.pt[p]), Pt(mesh.pt[r])), r});
insert(0, xn-1, {PtP(Pt(mesh.pt[p]), Pt(mesh.pt[q])), q});
insert(0, xn-1, {PtP(Pt(mesh.pt[q]), Pt(mesh.pt[r])), r});
}
void remove(tuple<int, int, int> e) {
int p, q, r; tie(p, q, r) = e;
remove(0, xn-1, {PtP(Pt(mesh.pt[p]), Pt(mesh.pt[q])), q});
remove(0, xn-1, {PtP(Pt(mesh.pt[q]), Pt(mesh.pt[r])), r});
insert(0, xn-1, {PtP(Pt(mesh.pt[p]), Pt(mesh.pt[r])), r});
}
int inside(double x, double y) {
PtP::x = x;
return count(root, 0, xn-1, x, y)&1;
}
int count(Node* u, int l, int r, double x, double y) {
if (u == NULL)
return 0;
int ret = 0;
if ((mesh.X[l] > x) != (mesh.X[r] > x))
ret += u->segs.order_of_key({PtP(Pt(x, y), Pt(x, y)), -1});
int m = (l+r)/2;
if (x <= mesh.X[m])
ret += count(u->lson, l, m, x, y);
if (x >= mesh.X[m])
ret += count(u->rson, m, r, x, y);
return ret;
}
void insert(int l, int r, pair<PtP, int> s) {
if (s.first.p.x != s.first.q.x)
insert(root, l, r, s);
}
void remove(int l, int r, pair<PtP, int> s) {
if (s.first.p.x != s.first.q.x)
remove(root, l, r, s);
}
void insert(Node* &u, int l, int r, pair<PtP, int> s) {
if (u == NULL)
u = newNode();
if (s.first.p.x <= mesh.X[l] && mesh.X[r] <= s.first.q.x) {
PtP::x = (mesh.X[l] + mesh.X[r])/2.0;
u->segs.insert(s);
return;
}
int m = (l+r)/2;
if (s.first.q.x <= mesh.X[m]) insert(u->lson, l, m, s);
else if (s.first.p.x >= mesh.X[m]) insert(u->rson, m, r, s);
else insert(u->lson, l, m, s), insert(u->rson, m, r, s);
}
void remove(Node* u, int l, int r, pair<PtP, int> s) {
if (u == NULL)
return;
if (s.first.p.x <= mesh.X[l] && mesh.X[r] <= s.first.q.x) {
PtP::x = (mesh.X[l] + mesh.X[r])/2.0;
u->segs.erase(s);
return;
}
int m = (l+r)/2;
if (s.first.q.x <= mesh.X[m]) remove(u->lson, l, m, s);
else if (s.first.p.x >= mesh.X[m]) remove(u->rson, m, r, s);
else remove(u->lson, l, m, s), remove(u->rson, m, r, s);
}
} mbrh;
int main() {
int n, m, cmd, x, pos;
double px, py;
scanf("%d %d", &n, &m);
mesh.read(n);
mlist.init(), mbrh.init();
for (int i = 0; i < m; i++) {
scanf("%d", &cmd);
if (cmd == 1) {
scanf("%d %d", &x, &pos);
mbrh.insert(mlist.insert(x, pos));
} else if (cmd == 2) {
scanf("%d", &x);
mbrh.remove(mlist.remove(x));
} else {
scanf("%lf %lf", &px, &py);
puts(mbrh.inside(px, py) ? "1" : "0");
}
}
return 0;
}