//#define MYDEBUG
#define _CRT_SECURE_NO_WARNINGS
#define TASK "C-small-attempt0"
#pragma comment(linker, "/STACK:536870912")
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <functional>
#include <cassert>
#include <bitset>
#include <unordered_set>
#include <unordered_map>
#include <random>

const int MOD = 1000000007;
const int INF = 1000000001;
const int MAXN = 100010;
const long double EPS = 1e-6;
const int HASH_POW = 29;
const long double PI = acos(-1.0);

using namespace std;

void my_return(int code)
{
#ifdef MYDEBUG
	cout << "\nTime = " << fixed << setprecision(3) << double(clock()) / CLOCKS_PER_SEC << endl;
#endif
	exit(code);
}

int n, a[100010], t[100010], x[100010], tmp[100010], res[100010];
vector <int> G[100010];

int main()
{
	cin.sync_with_stdio(0);
	cin.tie(0);
	mt19937 mt_rand(time(0));
#ifdef MYDEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#else
	/*freopen(TASK".in", "rt", stdin);
	freopen(TASK".out", "wt", stdout);*/
	/*freopen("input.txt", "rt", stdin);
	freopen("output.txt", "wt", stdout);*/
#endif

	scanf("%d", &n);
	for (int i = 0; i < n; ++i)
		scanf("%d %d %d", &a[i], &t[i], &x[i]);

	for (int i = 0; i < n; ++i)
		tmp[i] = x[i];
	sort(tmp, tmp + n);
	for (int i = 0; i < n; ++i)
	{
		int ll = -1, rr = n;
		while (ll + 1 < rr)
		{
			int mid = (ll + rr) / 2;
			if (tmp[mid] >= x[i])
				rr = mid;
			else
				ll = mid;
		}
		x[i] = rr + 1;
	}

	memset(res, -1, sizeof res);
	for (int i = 0; i < n; ++i)
		G[x[i]].push_back(i);
	for (int i = 1; i <= n; ++i)
	{
		if (G[i].empty())
			continue;
		vector <int> tr(G[i].size() + 1, 0);
		vector <int> cmp(G[i].size(), 0);
		for (int j = 0; j < G[i].size(); ++j)
			tmp[j] = t[G[i][j]];
		sort(tmp, tmp + G[i].size());
		for (int j = 0; j < G[i].size(); ++j)
		{
			int ll = -1, rr = G[i].size();
			while (ll + 1 < rr)
			{
				int mid = (ll + rr) / 2;
				if (tmp[mid] >= t[G[i][j]])
					rr = mid;
				else
					ll = mid;
			}
			cmp[j] = rr;
		}
		for (int j = 0; j < G[i].size(); ++j)
		{
			int id = G[i][j];
			if (a[id] == 1)
			{
				int x = cmp[j] + 1;
				for (; x <= G[i].size(); x += (x & (-x)))
					tr[x] += 1;
			}
			else if (a[id] == 2)
			{
				int x = cmp[j] + 1;
				for (; x <= G[i].size(); x += (x & (-x)))
					tr[x] -= 1;
			}
			else
			{
				int x = cmp[j] + 1, ans = 0;
				for (; x > 0; x -= (x & (-x)))
					ans += tr[x];
				res[G[i][j]] = ans;
			}
		}
	}
	for (int i = 0; i < n; ++i)
		if (res[i] != -1)
			printf("%d\n", res[i]);

	my_return(0);
}


#include <iostream>
#include <stdio.h>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
vector <int> vt,vx;
map <int,int> T,X;
int n,i,j,a[1000002],t[1000002],x[1000002];
int answ[1000002];
int p = 1;
vector < pair<int, pair<int,int> > > A[1000002];
vector <int> V;
int seg[4400000];
void poxel(int v,int s,int e,int h,int val)
{
    int m = (s+e)/2;
    V.push_back(v);
    if(s == e)
    {
        seg[v]+=val;
        return;
    }
    if(h<=m) poxel(v*2,s,m,h,val);
    else poxel(v*2+1,m+1,e,h,val);
    seg[v] = seg[v*2]+seg[v*2+1];
}
int gtnel(int v,int s,int e,int l,int r)
{
    int m = (s+e)/2;
    if(l>r) return 0;
    if(s == l && e == r) return seg[v];
    return gtnel(v*2,s,m,l,min(r,m)) + gtnel(v*2+1,m+1,e,max(l,m+1),r);
}
int main()
{
    scanf("%d", &n);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d", &a[i], &t[i], &x[i]);
        vt.push_back(t[i]);
        vx.push_back(x[i]);
    }
    sort(vt.begin(),vt.end());
    sort(vx.begin(),vx.end());
    for(i=0;i<vt.size();i++)
    {
        T[vt[i]] = i+1;
        X[vx[i]] = i+1;
    }
    for(i=1;i<=n;i++)
    {
        t[i] = T[t[i]];
        x[i] = X[x[i]];
        A[x[i]].push_back(make_pair(a[i],make_pair(t[i],p)));
        if(a[i] == 3) p++;
    }
    for(i=1;i<=n;i++)
    {
        V.clear();
        for(j=0;j<A[i].size();j++)
        {
            int a1,t1,h1;
            a1 = A[i][j].first;
            t1 = A[i][j].second.first;
            h1 = A[i][j].second.second;
            if(a1 == 1) poxel(1,1,n,t1,1);
            if(a1 == 2) poxel(1,1,n,t1,-1);
            if(a1 == 3) answ[h1] = gtnel(1,1,n,1,t1);
        }
        for(j=0;j<V.size();j++) seg[V[j]] = 0;
    }
    for(i=1;i<p;i++)
    {
        printf("%d\n", answ[i]);
    }
    return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#pragma comment(linker, "/STACK:256000000")
#include <stdio.h>
#include <limits.h>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <memory.h>
#include <string.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <functional>
#include <cassert>
#include <map>
#include <set>
#include <list>
#include <time.h>

using namespace std;
typedef long long lli;
typedef vector<int> vi;
typedef vector<lli> vli;
typedef pair<int, int> pii;
typedef vector<pii> vpii;
typedef long double ld;

const int INF = 0x3f3f3f3f;
const lli LINF = 0x3f3f3f3f3f3f3f3f;

//#define _LOCAL_DEBUG_
#ifdef _LOCAL_DEBUG_
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#else
#define eprintf(...)
#endif

const int MAX = 1e5 + 10;

#pragma region Treap
typedef pair<int, int> TValue;

struct TreapNode {
	TreapNode *l, *r, *p;
	lli y, size;
	TValue value;
	int d;
	int rangeSum;
	TreapNode() { }

	static int getSize(TreapNode *t) { return t == NULL ? 0 : t->size; }
	static int getRangeSum(TreapNode *t) { return t == NULL ? 0 : t->rangeSum; }
	static void update(TreapNode *t) {
		t->size = getSize(t->l) + getSize(t->r) + 1;
		t->rangeSum = getRangeSum(t->l) + getRangeSum(t->r) + t->d;
	}

	TreapNode(TValue _value, int d) : size(1), y((1LL << 32) * rand() + (1LL << 16) * rand() + rand()), value(_value), d(d) {
		l = r = p = NULL;
		update(this);
	}

	struct iterator {
		TreapNode* curr;
		iterator(TreapNode* _curr) : curr(_curr) {}
		iterator& operator++() {
			assert(curr != NULL);
			TreapNode *t = curr->r;
			if (t != NULL) while (t->l != NULL) t = t->l;
			else {
				for (t = curr; t->p != NULL && t->p->r == t; t = t->p);
				t = t->p;
			}
			curr = t;
			return *this;
		}
		bool operator != (const TreapNode::iterator &other) { return curr != other.curr; }
		bool operator == (const TreapNode::iterator &other) { return curr == other.curr; }
		TreapNode* operator *() { return curr; }
	};
};

const int MAXSTACKSIZE = 1e5 + 100;
struct TreapNodeStack {
	TreapNode stack[MAXSTACKSIZE];
	int size;
	TreapNodeStack() { size = 0; }
	TreapNode *getNext() { return &stack[size++]; }
};

struct Treap {
	static void updateSize(TreapNode *t) { assert(t != NULL); t->size = getSize(t->l) + getSize(t->r) + 1; }
	static int getSize(TreapNode *t) { return t == NULL ? 0 : t->size; }

	TreapNodeStack* s;
	TreapNode* root;
	Treap() { assert(false); }
	Treap(TreapNodeStack* _s) : s(_s), root(NULL) {}
	Treap(TreapNodeStack* _s, TreapNode* _root) : s(_s), root(_root) {}

	static TreapNode *merge(TreapNode *t1, TreapNode *t2) {
		if (t1 == NULL) return t2;
		if (t2 == NULL) return t1;
		TreapNode *t;
		if (t1->y > t2->y) {
			t = t1;
			t->r = merge(t->r, t2);
			t->r->p = t;
		}
		else { // <=
			t = t2;
			t->l = merge(t1, t->l);
			t->l->p = t;
		}
		TreapNode::update(t);
		return t;
	}

	static void splitByValue(TreapNode *t, TValue value, TreapNode* &L, TreapNode* &R) {
		if (t == NULL) return void(L = R = NULL);
		if (t->value < value) { // greaterOrEqual values go right
			splitByValue(t->r, value, t->r, R);
			if (t->r != NULL) t->r->p = t;
			if (R != NULL) R->p = NULL;
			L = t;
		}
		else { // lower values go left
			splitByValue(t->l, value, L, t->l);
			if (t->l != NULL) t->l->p = t;
			if (L != NULL) L->p = NULL;
			R = t;
		}
		TreapNode::update(t);
	}

	static void splitByIndex(TreapNode *t, int idx, TreapNode* &L, TreapNode* &R) {
		if (t == NULL) return void(L = R = NULL);
		int currentIndex = getSize(t->l);
		if (idx <= currentIndex) {
			splitByIndex(t->l, idx, L, t->l);
			if (t->l != NULL) t->l->p = t;
			if (L != NULL) L->p = NULL;
			R = t;
		}
		else {
			splitByIndex(t->r, idx - currentIndex - 1, t->r, R);
			if (t->r != NULL) t->r->p = t;
			if (R != NULL) R->p = NULL;
			L = t;
		}
		TreapNode::update(t);
	}

	TreapNode::iterator begin() {
		TreapNode *t = root;
		while (t != NULL && t->l != NULL) t = t->l;
		return TreapNode::iterator(t);
	}
	TreapNode::iterator end() { return TreapNode::iterator(NULL); }
	TreapNode::iterator lower_bound(TValue value) {
		TreapNode *l, *r, *t;
		splitByValue(root, value, l, r);
		for (t = r; t != NULL && t->l != NULL; t = t->l);
		TreapNode::iterator res = TreapNode::iterator(t);
		root = merge(l, r);
		return res;
	}

	TreapNode::iterator find(TreapNode* t, TValue value) {
		if (t == NULL) return this->end();
		if (t->value == value) return TreapNode::iterator(t);
		return t->value < value ? find(t->r, value) : find(t->l, value);
	}
	TreapNode::iterator find(TValue value) { return find(root, value); }

	TreapNode* operator[](int i) {
		assert(i < getSize(root) && i >= 0);
		TreapNode *l, *r, *t;
		splitByIndex(root, i, l, r);
		for (t = r; t != NULL && t->l != NULL; t = t->l);
		merge(l, r);
		return t;
	}

	void erase(TValue value) {
		if (find(value) == end()) return;
		TreapNode *l, *r, *tmp;
		splitByValue(root, value, l, r);
		splitByIndex(r, 1, tmp, r);
		root = merge(l, r);
	}

	void clear() {
		root = NULL;
	}

	size_t size() {
		return getSize(root);
	}

	void insert(TValue value, int d) {
		TreapNode *t = s->getNext();
		(*t) = TreapNode(value, d);
		TreapNode *l, *r;
		splitByValue(root, value, l, r);
		l = merge(l, t);
		root = merge(l, r);
	}

	lli getRangeResultForLowerValues(TValue value) {
		TreapNode *l, *r;
		splitByValue(root, value, l, r);
		lli res = TreapNode::getRangeSum(l);
		root = merge(l, r);
		return res;
	}

#pragma region out
	void out() {
		out(root);
	}
	void out(TreapNode *t, int lvl = 1) {
#ifndef _LOCAL_DEBUG_
		return;
#endif
		if (lvl == 1) eprintf("-------------------\n");
		if (t == NULL) return;
		out(t->l, lvl + 1);
		eprintf("%*c%d\n", lvl, ' ', t->value);
		out(t->r, lvl + 1);
	}
#pragma endregion
};
#pragma endregion

int nq;
TreapNodeStack st;

void clear() {
}

int getRng(Treap &t, int x, int time) {
	TreapNode *l, *r;
	Treap::splitByValue(t.root, make_pair(x, 0), l, r);
	TreapNode *lr, *rr;
	Treap::splitByValue(r, make_pair(x, time), lr, rr);
	int res = TreapNode::getRangeSum(lr);
	r = Treap::merge(lr, rr);
	t.root = Treap::merge(l, r);
	return res;
}

void solve() {
	Treap t1(&st);
	Treap t2(&st);
	for (int i = 0; i < nq; i++) {
		int type, time, x;
		scanf("%d%d%d", &type, &time, &x);
		if (type == 1) {
			t1.insert(make_pair(x, time), 1);
		}
		else if (type == 2) {
			t2.insert(make_pair(x, time), 1);
		}
		else {
			int l = getRng(t1, x, time);
			int r = getRng(t2, x, time);
			int res = l - r;
			assert(res >= 0);
			printf("%d\n", res);
		}
	}
}

int main() {
	srand(432);
#ifdef _LOCAL_VAN
	freopen("in.txt", "r", stdin);
#endif
	scanf("%d", &nq);
	clear();
	solve();

	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#pragma comment(linker, "/STACK:256000000")
#include <stdio.h>
#include <limits.h>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <memory.h>
#include <string.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <functional>
#include <cassert>
#include <map>
#include <set>
#include <list>
#include <time.h>

using namespace std;
typedef long long lli;
typedef vector<int> vi;
typedef vector<lli> vli;
typedef pair<int, int> pii;
typedef vector<pii> vpii;
typedef long double ld;

const int INF = 0x3f3f3f3f;
const lli LINF = 0x3f3f3f3f3f3f3f3f;

//#define _LOCAL_DEBUG_
#ifdef _LOCAL_DEBUG_
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#else
#define eprintf(...)
#endif

const int MAX = 1e5 + 10;

#pragma region Treap
typedef pair<int, int> TValue;

struct TreapNode {
	TreapNode *l, *r, *p;
	lli y, size;
	TValue value;
	int d;
	int rangeSum;
	TreapNode() { }

	static int getSize(TreapNode *t) { return t == NULL ? 0 : t->size; }
	static int getRangeSum(TreapNode *t) { return t == NULL ? 0 : t->rangeSum; }
	static void update(TreapNode *t) {
		t->size = getSize(t->l) + getSize(t->r) + 1;
		t->rangeSum = getRangeSum(t->l) + getRangeSum(t->r) + t->d;
	}

	TreapNode(TValue _value, int d) : size(1), y((1LL << 32) * rand() + (1LL << 16) * rand() + rand()), value(_value), d(d) {
		l = r = p = NULL;
		update(this);
	}

	struct iterator {
		TreapNode* curr;
		iterator(TreapNode* _curr) : curr(_curr) {}
		iterator& operator++() {
			assert(curr != NULL);
			TreapNode *t = curr->r;
			if (t != NULL) while (t->l != NULL) t = t->l;
			else {
				for (t = curr; t->p != NULL && t->p->r == t; t = t->p);
				t = t->p;
			}
			curr = t;
			return *this;
		}
		bool operator != (const TreapNode::iterator &other) { return curr != other.curr; }
		bool operator == (const TreapNode::iterator &other) { return curr == other.curr; }
		TreapNode* operator *() { return curr; }
	};
};

const int MAXSTACKSIZE = 1e5 + 100;
struct TreapNodeStack {
	TreapNode stack[MAXSTACKSIZE];
	int size;
	TreapNodeStack() { size = 0; }
	TreapNode *getNext() { return &stack[size++]; }
};

struct Treap {
	static void updateSize(TreapNode *t) { assert(t != NULL); t->size = getSize(t->l) + getSize(t->r) + 1; }
	static int getSize(TreapNode *t) { return t == NULL ? 0 : t->size; }

	TreapNodeStack* s;
	TreapNode* root;
	Treap() { assert(false); }
	Treap(TreapNodeStack* _s) : s(_s), root(NULL) {}
	Treap(TreapNodeStack* _s, TreapNode* _root) : s(_s), root(_root) {}

	static TreapNode *merge(TreapNode *t1, TreapNode *t2) {
		if (t1 == NULL) return t2;
		if (t2 == NULL) return t1;
		TreapNode *t;
		if (t1->y > t2->y) {
			t = t1;
			t->r = merge(t->r, t2);
			t->r->p = t;
		}
		else { // <=
			t = t2;
			t->l = merge(t1, t->l);
			t->l->p = t;
		}
		TreapNode::update(t);
		return t;
	}

	static void splitByValue(TreapNode *t, TValue value, TreapNode* &L, TreapNode* &R) {
		if (t == NULL) return void(L = R = NULL);
		if (t->value < value) { // greaterOrEqual values go right
			splitByValue(t->r, value, t->r, R);
			if (t->r != NULL) t->r->p = t;
			if (R != NULL) R->p = NULL;
			L = t;
		}
		else { // lower values go left
			splitByValue(t->l, value, L, t->l);
			if (t->l != NULL) t->l->p = t;
			if (L != NULL) L->p = NULL;
			R = t;
		}
		TreapNode::update(t);
	}

	static void splitByIndex(TreapNode *t, int idx, TreapNode* &L, TreapNode* &R) {
		if (t == NULL) return void(L = R = NULL);
		int currentIndex = getSize(t->l);
		if (idx <= currentIndex) {
			splitByIndex(t->l, idx, L, t->l);
			if (t->l != NULL) t->l->p = t;
			if (L != NULL) L->p = NULL;
			R = t;
		}
		else {
			splitByIndex(t->r, idx - currentIndex - 1, t->r, R);
			if (t->r != NULL) t->r->p = t;
			if (R != NULL) R->p = NULL;
			L = t;
		}
		TreapNode::update(t);
	}

	TreapNode::iterator begin() {
		TreapNode *t = root;
		while (t != NULL && t->l != NULL) t = t->l;
		return TreapNode::iterator(t);
	}
	TreapNode::iterator end() { return TreapNode::iterator(NULL); }
	TreapNode::iterator lower_bound(TValue value) {
		TreapNode *l, *r, *t;
		splitByValue(root, value, l, r);
		for (t = r; t != NULL && t->l != NULL; t = t->l);
		TreapNode::iterator res = TreapNode::iterator(t);
		root = merge(l, r);
		return res;
	}

	TreapNode::iterator find(TreapNode* t, TValue value) {
		if (t == NULL) return this->end();
		if (t->value == value) return TreapNode::iterator(t);
		return t->value < value ? find(t->r, value) : find(t->l, value);
	}
	TreapNode::iterator find(TValue value) { return find(root, value); }

	TreapNode* operator[](int i) {
		assert(i < getSize(root) && i >= 0);
		TreapNode *l, *r, *t;
		splitByIndex(root, i, l, r);
		for (t = r; t != NULL && t->l != NULL; t = t->l);
		merge(l, r);
		return t;
	}

	void erase(TValue value) {
		if (find(value) == end()) return;
		TreapNode *l, *r, *tmp;
		splitByValue(root, value, l, r);
		splitByIndex(r, 1, tmp, r);
		root = merge(l, r);
	}

	void clear() {
		root = NULL;
	}

	size_t size() {
		return getSize(root);
	}

	void insert(TValue value, int d) {
		TreapNode *t = s->getNext();
		(*t) = TreapNode(value, d);
		TreapNode *l, *r;
		splitByValue(root, value, l, r);
		l = merge(l, t);
		root = merge(l, r);
	}

	lli getRangeResultForLowerValues(TValue value) {
		TreapNode *l, *r;
		splitByValue(root, value, l, r);
		lli res = TreapNode::getRangeSum(l);
		root = merge(l, r);
		return res;
	}

#pragma region out
	void out() {
		out(root);
	}
	void out(TreapNode *t, int lvl = 1) {
#ifndef _LOCAL_DEBUG_
		return;
#endif
		if (lvl == 1) eprintf("-------------------\n");
		if (t == NULL) return;
		out(t->l, lvl + 1);
		eprintf("%*c%d\n", lvl, ' ', t->value);
		out(t->r, lvl + 1);
	}
#pragma endregion
};
#pragma endregion

int nq;
TreapNodeStack st;

void clear() {
}

int getRng(Treap &t, int x, int time) {
	TreapNode *l, *r;
	Treap::splitByValue(t.root, make_pair(x, 0), l, r);
	TreapNode *lr, *rr;
	Treap::splitByValue(r, make_pair(x, time), lr, rr);
	int res = TreapNode::getRangeSum(lr);
	r = Treap::merge(lr, rr);
	t.root = Treap::merge(l, r);
	return res;
}

void solve() {
	Treap t1(&st);
	Treap t2(&st);
	for (int i = 0; i < nq; i++) {
		int type, time, x;
		scanf("%d%d%d", &type, &time, &x);
		if (type == 1) {
			t1.insert(make_pair(x, time), 1);
		}
		else if (type == 2) {
			t2.insert(make_pair(x, time), 1);
		}
		else {
			int l = getRng(t1, x, time);
			int r = getRng(t2, x, time);
			int res = l - r;
			assert(res >= 0);
			printf("%d\n", res);
		}
	}
}

int main() {
	srand(time(NULL));
#ifdef _LOCAL_VAN
	freopen("in.txt", "r", stdin);
#endif
	scanf("%d", &nq);
	clear();
	solve();

	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#pragma comment(linker, "/STACK:256000000")
#include <stdio.h>
#include <limits.h>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <memory.h>
#include <string.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <functional>
#include <cassert>
#include <map>
#include <set>
#include <list>
#include <time.h>

using namespace std;
typedef long long lli;
typedef vector<int> vi;
typedef vector<lli> vli;
typedef pair<int, int> pii;
typedef vector<pii> vpii;
typedef long double ld;

const int INF = 0x3f3f3f3f;
const lli LINF = 0x3f3f3f3f3f3f3f3f;

//#define _LOCAL_DEBUG_
#ifdef _LOCAL_DEBUG_
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#else
#define eprintf(...)
#endif

const int MAX = 1e5 + 10;

#pragma region Treap
typedef pair<int, int> TValue;

struct TreapNode {
	TreapNode *l, *r, *p;
	int y;
	int rangeSize;
	int d;
	TValue value;
	int rangeValue;
	TreapNode() { }

	static int getRangeSize(TreapNode *t) { return t == NULL ? 0 : t->rangeSize; }
	static int getRangeValue(TreapNode *t) { return t == NULL ? 0 : t->rangeValue; }
	static void update(TreapNode *t) {
		t->rangeSize = getRangeSize(t->l) + getRangeSize(t->r) + 1;
		t->rangeValue = getRangeValue(t->l) + getRangeValue(t->r) + t->d;
	}

	TreapNode(TValue _value, int d) : d(d), y((1 << 16) * rand() + rand()), value(_value) {
		l = r = p = NULL;
		update(this);
	}

	struct iterator {
		TreapNode* curr;
		iterator(TreapNode* _curr) : curr(_curr) {}
		iterator& operator++() {
			assert(curr != NULL);
			TreapNode *t = curr->r;
			if (t != NULL) while (t->l != NULL) t = t->l;
			else {
				for (t = curr; t->p != NULL && t->p->r == t; t = t->p);
				t = t->p;
			}
			curr = t;
			return *this;
		}
		bool operator != (const TreapNode::iterator &other) { return curr != other.curr; }
		bool operator == (const TreapNode::iterator &other) { return curr == other.curr; }
		TreapNode* operator *() { return curr; }
	};
};

const int MAXSTACKSIZE = 1e5 + 100;
struct TreapNodeStack {
	TreapNode stack[MAXSTACKSIZE];
	int size;
	TreapNodeStack() { size = 0; }
	TreapNode *getNext() { return &stack[size++]; }
};

struct Treap {

	TreapNodeStack* s;
	TreapNode* root;
	Treap(TreapNodeStack* _s) : s(_s), root(NULL) {}
	Treap(TreapNodeStack* _s, TreapNode* _root) : s(_s), root(_root) {}

	static TreapNode *merge(TreapNode *t1, TreapNode *t2) {
		if (t1 == NULL) return t2;
		if (t2 == NULL) return t1;
		TreapNode *t;
		if (t1->y > t2->y) {
			t = t1;
			t->r = merge(t->r, t2);
			t->r->p = t;
		}
		else { // <=
			t = t2;
			t->l = merge(t1, t->l);
			t->l->p = t;
		}
		TreapNode::update(t);
		return t;
	}

	static void splitByValue(TreapNode *t, TValue value, TreapNode* &L, TreapNode* &R) {
		if (t == NULL) return void(L = R = NULL);
		if (t->value < value) { // greaterOrEqual values go right
			splitByValue(t->r, value, t->r, R);
			if (t->r != NULL) t->r->p = t;
			if (R != NULL) R->p = NULL;
			L = t;
		}
		else { // lower values go left
			splitByValue(t->l, value, L, t->l);
			if (t->l != NULL) t->l->p = t;
			if (L != NULL) L->p = NULL;
			R = t;
		}
		TreapNode::update(t);
	}

	static void splitByIndex(TreapNode *t, int idx, TreapNode* &L, TreapNode* &R) {
		if (t == NULL) return void(L = R = NULL);
		int currentIndex = TreapNode::getRangeSize(t->l);
		if (idx <= currentIndex) {
			splitByIndex(t->l, idx, L, t->l);
			if (t->l != NULL) t->l->p = t;
			if (L != NULL) L->p = NULL;
			R = t;
		}
		else {
			splitByIndex(t->r, idx - currentIndex - 1, t->r, R);
			if (t->r != NULL) t->r->p = t;
			if (R != NULL) R->p = NULL;
			L = t;
		}
		TreapNode::update(t);
	}

	TreapNode::iterator begin() {
		TreapNode *t = root;
		while (t != NULL && t->l != NULL) t = t->l;
		return TreapNode::iterator(t);
	}
	TreapNode::iterator end() { return TreapNode::iterator(NULL); }
	TreapNode::iterator lower_bound(TValue value) {
		TreapNode *l, *r, *t;
		splitByValue(root, value, l, r);
		for (t = r; t != NULL && t->l != NULL; t = t->l);
		TreapNode::iterator res = TreapNode::iterator(t);
		root = merge(l, r);
		return res;
	}

	TreapNode::iterator find(TreapNode* t, TValue value) {
		if (t == NULL) return this->end();
		if (t->value == value) return TreapNode::iterator(t);
		return t->value < value ? find(t->r, value) : find(t->l, value);
	}
	TreapNode::iterator find(TValue value) { return find(root, value); }

	TreapNode* operator[](int i) {
		assert(i < TreapNode::getRangeSize(root) && i >= 0);
		TreapNode *l, *r, *t;
		splitByIndex(root, i, l, r);
		for (t = r; t != NULL && t->l != NULL; t = t->l);
		merge(l, r);
		return t;
	}

	void erase(TValue value) {
		if (find(value) == end()) return;
		TreapNode *l, *r, *tmp;
		splitByValue(root, value, l, r);
		splitByIndex(r, 1, tmp, r);
		root = merge(l, r);
	}

	void clear() {
		root = NULL;
	}

	size_t size() {
		return TreapNode::getRangeSize(root);
	}

	void insert(TValue value, int d) {
		TreapNode *t = s->getNext();
		(*t) = TreapNode(value, d);
		TreapNode *l, *r;
		splitByValue(root, value, l, r);
		l = merge(l, t);
		root = merge(l, r);
	}

#pragma region out
	void out() {
		out(root);
	}
	void out(TreapNode *t, int lvl = 1) {
#ifndef _LOCAL_DEBUG_
		return;
#endif
		if (lvl == 1) eprintf("-------------------\n");
		if (t == NULL) return;
		out(t->l, lvl + 1);
		eprintf("%*c%d\n", lvl, ' ', t->value);
		out(t->r, lvl + 1);
	}
#pragma endregion
};
#pragma endregion

int nq;
TreapNodeStack st;

void clear() {
}

int getRng(Treap &t, int x, int time) {
	TreapNode *l, *r;
	Treap::splitByValue(t.root, make_pair(x, 0), l, r);
	TreapNode *lr, *rr;
	Treap::splitByValue(r, make_pair(x, time), lr, rr);
	int res = TreapNode::getRangeValue(lr);
	r = Treap::merge(lr, rr);
	t.root = Treap::merge(l, r);
	return res;
}

void solve() {
	Treap t1(&st);
	Treap t2(&st);
	for (int i = 0; i < nq; i++) {
		int type, time, x;
		scanf("%d%d%d", &type, &time, &x);
		if (type == 1) {
			t1.insert(make_pair(x, time), 1);
		}
		else if (type == 2) {
			t2.insert(make_pair(x, time), 1);
		}
		else {
			int l = getRng(t1, x, time);
			int r = getRng(t2, x, time);
			int res = l - r;
			assert(res >= 0);
			printf("%d\n", res);
		}
	}
}

int main() {
	srand(time(NULL));
#ifdef _LOCAL_VAN
	freopen("in.txt", "r", stdin);
#endif
	scanf("%d", &nq);
	clear();
	solve();

	return 0;
}


#pragma comment(linker, "/STACK:100000000")
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <sstream>
#include <queue>
#include <algorithm>
#include <iostream>
#include <stack>
using namespace std;

typedef long long ll;
#define mod 1000000007
#define INF mod
#define pi acos(-1.0)
#define LINF 1000000000000000000LL
#define eps 1e-10

#define START 131072

struct triple
{
	int a, t, i;
};

int n;
int tr[2*START+5];
map <int, vector <triple> > mp;
vector <pair <int, int> > res;

int sum(int L, int R)
{
	L += START; R += START;
	int res = 0;
	while(L <= R)
	{
		if(L & 1) res += tr[L++];
		if(~R & 1) res += tr[R--];
		L >>= 1; R >>= 1;
	}
	return res;
}

int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i++)
	{
		int x;
		triple z;
		scanf("%d %d %d", &z.a, &z.t, &x);
		z.i = i;
		mp[x].push_back(z);
	}
	for(map <int, vector <triple> >::iterator it = mp.begin(); it != mp.end(); ++it)
	{
		vector <triple>& v = it->second;
		map <int, int> tt;
		int cnt = 1;
		for(int i = 0; i < v.size(); i++)
		{
			tt[v[i].t] = 1;
		}
		for(map<int, int> :: iterator it2 = tt.begin(); it2 != tt.end(); ++it2, cnt++)
			it2->second = cnt;
		for(int i = 0; i < v.size(); i++)
		{
			v[i].t = tt[v[i].t];
		}
		for(int i = 0; i < v.size(); i++)
		{
			if(v[i].a <= 2)
			{
				int c = v[i].a == 1 ? 1 : -1;
				tr[START + v[i].t] += c;
				for(int j = ((START + v[i].t) >> 1); j > 0; j >>= 1)
					tr[j] = tr[(j<<1)] + tr[(j<<1)+1];
			}
			else
			{
				res.push_back(make_pair(v[i].i, sum(0, v[i].t)));
			}
		}
		for(int i = 0; i < v.size(); i++)
		{
			if(v[i].a <= 2)
			{
				tr[START + v[i].t] = 0;
				for(int j = ((START + v[i].t) >> 1); j > 0; j >>= 1)
					tr[j] = tr[(j<<1)] + tr[(j<<1)+1];
			}
		}
	}
	sort(res.begin(), res.end());
	for(int i = 0; i < res.size(); i++)
		printf("%d\n", res[i].second);
	return 0;
}


#pragma comment(linker, "/STACK:100000000")
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <sstream>
#include <queue>
#include <algorithm>
#include <iostream>
#include <stack>
using namespace std;

typedef long long ll;
#define mod 1000000007
#define INF mod
#define pi acos(-1.0)
#define LINF 1000000000000000000LL
#define eps 1e-10

#define START 1048576

struct triple
{
	int a, t, i;
};

int n;
int tr[2*START+5];
map <int, vector <triple> > mp;
map <int, int> tt;
vector <pair <int, int> > res;

int sum(int L, int R)
{
	L += START; R += START;
	int res = 0;
	while(L <= R)
	{
		if(L & 1) res += tr[L++];
		if(~R & 1) res += tr[R--];
		L >>= 1; R >>= 1;
	}
	return res;
}

int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i++)
	{
		int x;
		triple z;
		scanf("%d %d %d", &z.a, &z.t, &x);
		z.i = i;
		mp[x].push_back(z);
	}
	for(map <int, vector <triple> >::iterator it = mp.begin(); it != mp.end(); it++)
	{
		vector <triple> v = it->second;
		tt.clear();
		int cnt = 1;
		for(int i = 0; i < v.size(); i++)
		{
			tt[v[i].t] = 1;
		}
		for(map<int, int> :: iterator it = tt.begin(); it != tt.end(); it++, cnt++)
			it->second = cnt;
		for(int i = 0; i < v.size(); i++)
		{
			v[i].t = tt[v[i].t];
		}
		memset(tr, 0, sizeof(tr));
		for(int i = 0; i < v.size(); i++)
		{
			if(v[i].a <= 2)
			{
				int c = v[i].a == 1 ? 1 : -1;
				tr[START + v[i].t] += c;
				for(int j = (START + v[i].t) / 2; j > 0; j /= 2)
					tr[j] = tr[j*2] + tr[j*2+1];
			}
			else
			{
				res.push_back(make_pair(v[i].i, sum(0, v[i].t)));
			}
		}
	}
	sort(res.begin(), res.end());
	for(int i = 0; i < res.size(); i++)
		printf("%d\n", res[i].second);
	return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <cassert>
#include <algorithm>
#include <iomanip>
#include <ctime>
#include <cmath>
#include <bitset>

#pragma comment(linker, "/STACK:256000000")

using namespace std;

typedef long long int int64;
typedef long double double80;

const int INF = (1 << 29) + 5;
const int64 LLINF = (1ll << 59) + 5;
const int MOD = 1000 * 1000 * 1000 + 7;
const int MAX_N = 1000 * 1000 + 5;

struct node
{
	int value;
	int size;
	int y;
	node *l;
	node *r;

	node(int _value)
	{
		value = _value;
		y = ((rand() << 15) | rand());
		size = 1;
		l = nullptr;
		r = nullptr;
	}
};

void print(node *t)
{
	if (t == nullptr)
	{
		return;
	}
	else
	{
		print(t->l);
		printf("%d ", t->value);
		print(t->r);
	}
}

int get_size(node *t)
{
	if (t == nullptr)
	{
		return 0;
	}
	else
	{
		return t->size;
	}
}

void upd(node* &t)
{
	t->size = get_size(t->l) + get_size(t->r) + 1;
}

node* merge(node *t1, node *t2)
{
	if (t1 == nullptr)
	{
		return t2;
	}
	else if (t2 == nullptr)
	{
		return t1;
	}
	else
	{
		if (t1->y > t2->y)
		{
			t1->r = merge(t1->r, t2);
			upd(t1);
			return t1;
		}
		else
		{
			t2->l = merge(t1, t2->l);
			upd(t2);
			return t2;
		}
	}
}

void split(node *t, node* &t1, node* &t2, int x)
{
	if (t == nullptr)
	{
		t1 = nullptr;
		t2 = nullptr;
	}
	else
	{
		if (t->value < x)
		{
			split(t->r, t->r, t2, x);
			t1 = t;
		}
		else
		{
			split(t->l, t1, t->l, x);
			t2 = t;
		}
		upd(t);
	}
}

struct mm
{
	int type;
	int x;
	int time;
	int real_time;

	mm()
	{
	}

	mm(int _type, int _x, int _time)
	{
		type = _type;
		x = _x;
		time = _time;
	}
};

struct ans
{
	int time;
	int x;

	ans()
	{

	}

	ans(int _x, int _time)
	{
		x = _x;
		time = _time;
	}
};

bool cmp(const mm &a, const mm &b)
{
	return a.time < b.time;
}

bool cmp2(const ans &a, const ans &b)
{
	return a.time < b.time;
}

int n;
mm arr[MAX_N];
node* at_number[MAX_N];
node* del_number[MAX_N];
vector<ans> answer;
set<int> xx;
map<int, int> new_of;

int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);

	scanf("%d", &n);

	for (int i = 0; i < n; ++i)
	{
		scanf("%d %d %d", &arr[i].type, &arr[i].time, &arr[i].x);
		xx.insert(arr[i].x);
		arr[i].real_time = i;
	}

	int gg = 0;
	for (auto it = xx.begin(); it != xx.end(); ++it)
	{
		new_of[*it] = gg;
		++gg;
	}
	for (int i = 0; i < n; ++i)
	{
		arr[i].x = new_of[arr[i].x];
	}
	for (int i = 0; i < gg; ++i)
	{
		at_number[i] = nullptr;
		del_number[i] = nullptr;
	}

	sort(arr, arr + n, cmp);

	node *t1, *t2, *t3, *t4;
	for (int i = 0; i < n; ++i)
	{
		if (arr[i].type == 1)
		{
			split(at_number[arr[i].x], t1, t2, arr[i].real_time);
			at_number[arr[i].x] = merge(merge(t1, new node(arr[i].real_time)), t2);
		}
		else if (arr[i].type == 2)
		{
			split(del_number[arr[i].x], t1, t2, arr[i].real_time);
			del_number[arr[i].x] = merge(merge(t1, new node(arr[i].real_time)), t2);
		}
		else
		{
			split(at_number[arr[i].x], t1, t2, arr[i].real_time);
			split(del_number[arr[i].x], t3, t4, arr[i].real_time);
			answer.push_back(ans(get_size(t1) - get_size(t3), arr[i].real_time));
			at_number[arr[i].x] = merge(t1, t2);
			del_number[arr[i].x] = merge(t3, t4);
		}
	}

	sort(answer.begin(), answer.end(), cmp2);

	for (int i = 0; i < answer.size(); ++i)
	{
		printf("%d\n", answer[i].x);
	}

	fclose(stdin);
	fclose(stdout);

	return 0;
}


#pragma comment (linker, "/STACK:256000000")

#define _USE_MATH_DEFINES
#define _CRT_NO_DEPRECEATE
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <vector>
#include <utility>
#include <algorithm>
#include <functional>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <cmath>
#include <queue>
#include <memory.h>
#include <sstream>
#include <cassert>
#include <ctime>
#include <complex>
#include <random>

using namespace std;

typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
typedef long double ldouble;
typedef pair<int, int> pii;
typedef pair<int64, int64> pll;
typedef pair<pii, pii> piiii;

#define pb push_back
#define sq(x) ((x)*(x))
#define tmin(x,y,z) (min(min((x),(y)),(z)))
#define rand32() (((unsigned int)(rand()) << 16) | (unsigned int)(rand()))
#define rand64() (((unsigned int64)(rand32()) << 16) | (unsigned int64)(rand32()))
#define bit(mask, b) ((mask >> b) & 1)
#define biton(mask, bit) (mask | (((uint64)(1)) << bit))
#define bitoff(mask, bit) (mask & (~(((uint64)(1)) << bit)))
#define bitputon(mask, bit) (mask |= (((uint64)(1)) << bit))
#define bitputoff(mask, bit) (mask &= (~(((uint64)(1)) << bit)))
#define FAIL() (*((int*)(0)))++
#define INF ((int)(1e9) + 1337)
#define LINF ((int64)(1e18))
#define EPS 1e-9
#define PI (3.1415926535897932384626433832795)
#define y1 yy1
#define y0 yy0
#define j0 jj0
#define MOD 1000000007LL
#define HMOD 1234567913LL
#define HBASE 1009

//#define HMOD ((int64)(1e18) + 3LL)
//#ifdef _MY_DEBUG
//#define HMOD 1000000007
//#endii
#define MAX 2000000000
mt19937 ggen;

#define BMOD (10000000LL)
#define BSZ (7)

typedef int64 node;
struct tree
{
    int n;
    vector<node> t;
    tree() {}
    tree(int n) : n(n)
    {
        t.assign(4 * n + 10, 0);
    }
    tree(int n, node a[]) : n(n)
    {
        t.assign(4 * n + 10, 0);
    }

    inline void pull(int tv)
    {
        t[tv] = t[2 * tv] + t[2 * tv + 1];
    }

    int64 get(int tv, int tl, int tr, int l, int r)
    {
        if (l > r)
            return 0;
        if (tl == l && tr == r)
            return t[tv];
        else
        {
            int tm = (tl + tr) / 2;
            return get(2 * tv, tl, tm, l, min(r, tm)) +
                get(2 * tv + 1, tm + 1, tr, max(tm + 1, l), r);
        }
    }

    void add(int tv, int tl, int tr, int pos, int val)
    {
        if (tl == tr)
            t[tv] += val;
        else
        {
            int tm = (tl + tr) / 2;
            if (pos <= tm)
                add(2 * tv, tl, tm, pos, val);
            else
                add(2 * tv + 1, tm + 1, tr, pos, val);
            pull(tv);
        }
    }

    void add(int pos, int val)
    {
        return add(1, 0, n - 1, pos, val);
    }

    int64 get(int l, int r)
    {
        return get(1, 0, n - 1, l, r);
    }
};

struct query
{
    int a, t, x;
};

int n, m;
vector<query> q;
unordered_map<int, int> vals;
vector<vector<int> > tv;
vector<tree> tr;

void solve()
{
    scanf("%d", &n);
    q.resize(n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d%d", &q[i].a, &q[i].t, &q[i].x);
        if (!vals.count(q[i].x))
        {
            int t = vals.size();
            vals[q[i].x] = t;
        }
    }
    m = vals.size();
    tv.resize(m);
    for (int i = 0; i < n; i++)
    {
        int x = vals[q[i].x];
        tv[x].push_back(q[i].t);
    }
    tr.reserve(m);
    for (int i = 0; i < m; i++)
    {
        sort(tv[i].begin(), tv[i].end());
        tr.push_back(tree(tv[i].size()));
    }
    for (int i = 0; i < n; i++)
    {
        int x = vals[q[i].x];
        int t = lower_bound(tv[x].begin(), tv[x].end(), q[i].t) - tv[x].begin();
        if(q[i].a == 1)
            tr[x].add(t, 1);
        else if (q[i].a == 2)
            tr[x].add(t, -1);
        else
            printf("%d\n", tr[x].get(0, t));
    }
}

#define TASK "substr"
int main()
{
    //stresstest(50, 100, 70); return 0;
    //testgen(6);// return 0;
    ios_base::sync_with_stdio(false); cin.tie(0);
#ifdef _MY_DEBUG
    freopen("input.txt", "rt", stdin); freopen("output.txt", "wt", stdout);
#else
    //freopen(TASK ".in", "rt", stdin); freopen(TASK ".out", "wt", stdout);
#endif
    //stresstest(); return 0;
    srand(1313);
    ggen = mt19937(13);

    solve();

    return 0;
}


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <map>

using namespace std;
map<int,map<int, int>>g;
void main()
{
	int n;
	cin >> n;

	int inf = 1000000001;
	for (int i = 0; i < n; ++i)
	{
		int a, b, c;
		cin >> a >> b >> c;
		if (a == 1)
		{
				g[c][b]++;
		}
		if (a == 2)
		{
			int f = 0;
			for (int j = 0; j< b; ++j)
				if ((g[c][j] != 0) && (f == 0))
				{
					g[c][j] = 0;
					f = 1;
				}
		}
		if (a == 3)
		{
			int kol = 0;
			for (int j = 0; j< b;++j)
			if (g[c][j] !=0)
				kol += 1;
			cout << kol << endl;
		}
	}
}


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <map>

using namespace std;
map<int, map<int, int>>g;

void main()
{

	int max = 1000000001;
	int n, a, b, x, kol;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> b >> x;
		if (a == 1)
		{
			for (; b < max;)
			{
				g[x][b]++;
				b += (b & -b);
			}
		}
		if (a == 2)
		{
			for (; b < max;)
			{
				g[x][b]--;
				b += (b & -b);
			}
		}
		if (a == 3)
		{
			for (kol = 0; b > 0; b -= (b & -b))
				kol += g[x][b];
			cout << kol << endl;
		}

	}
}


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <map>

using namespace std;
map<int, map<int, int>>g;
void main()
{

	int max = 1000000001;
	int n, a, b, x, kol;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> b >> x;
		if (a == 1)
		{
			for (; b < max;)
			{
				g[x][b]++;
				b += (b & -b);
			}
		}
		if (a == 2)
		{
			for (; b < max; )
			{
				g[x][b]--;
				b += (b & -b);
			}
		}
		if (a == 3)
		{
			for (kol = 0; b > 0; b -=(b & -b))
				kol += g[x][b];
			cout << kol << endl;
		}

	}
}


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <map>

using namespace std;
map<int,map<int, int>>g;
void main()
{
	int n;
	cin >> n;

	int inf = 1000000001;
	for (int i = 0; i < n; ++i)
	{
		int a, b, c;
		cin >> a >> b >> c;
		if (a == 1)
		{
				g[c][b]++;
		}
		if (a == 2)
		{
			int f = 0,k=1,f1=1,l;
			for (int j = 0; j < b; ++j)
			{
				if (g[c][j] != 0)
				{
					if (f1 == 1)
					{
						f1 = 0;
						l = j;
					}
					f++;
				}
				if ((f == 2) && (k == 1))
				{
					k = 0;
					g[c][l] = 0;
				}
			}
		}
		if (a == 3)
		{
			int kol = 0;
			for (int j = 0; j< b;++j)
			if (g[c][j] !=0)
				kol += 1;
			cout << kol << endl;
		}
	}
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int  x, a, t;
long int n;
map<int, vector<int>> dec_sum;
const long int MAX_t =1000000000-1;
long int len = long int(10000*sqrt(10));
long int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	cin >> n;
	if (MAX_t%len != 0)
		size = long int(MAX_t / len) + 1;
	else  size =long int(MAX_t / len);

	for (long int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(n / len);
	if (n%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if (T[i] % len != 0)
			for (int h = T[i]; h%len != 0; h++)
				ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(n / len);
	if (max_t%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if (T[i] % len != 0)
			for (int h = T[i]; h%len != 0; h++)
				ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}

}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
const int len = 2;
map<int, map<int, int> > m;

int get_right_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	//if (y == t) return int(y*x);
	if (t == 1) return x;
	return int(y);
}
int get_left_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	if (y == t) return int(y);
	return int(y/x);
}
int get_ans(int x, int T)
{
	long int p=1;
	int  t = get_left_degree(T);
	if (t*len == T)
		return m[x][T];
	else
	{
		int r = m[x][T];
		if (T%len == 0) p = len;
		while (T != t)
		{
			T -= p;
			p *= len;
			r += m[x][T];
			if (m[x][T] == 0) m[x].erase(T);
		}
		return r;
	}
}
void increment(int x, int T)
{
	long int t = get_right_degree(T);
	long int p = 1;
	if (T%len == 0) p = len;
	m[x][T]++;
	while (T<t)
	{
		T += p;
		p *= len;
		m[x][T]++;
	}
	while ( T < inf)
	{
		T *= len;
		m[x][T]++;
	}
	m[x].erase(T);
}
void decrement(int x, int T)
{
	long int t = get_right_degree(T);
	long int p = 1;
	if (T%len == 0) p = len;
	m[x][T]--;
	while (T < t)
	{
		T += p;
		p *= len;
		m[x][T]--;
	}
	while (T < inf)
	{
		T *= len;
		m[x][T]--;
	}
	m[x].erase(T);
}

int main()
{
	int n, a, t, x, r;
	cin >> n;

	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
const int len = 2;
map<int, map<int, int> > m;

int get_right_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	if (y == t) return int(y*x);
	return int(y);
}
int get_left_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	return int(y/x);
}
int get_ans(int x, int T)
{
	int  t = get_left_degree(T);
	if (t*len == T)
		return m[x][t];
	else
	{
		int r = 0;
		while (T >= t)
		{
			r += m[x][T];
			if (m[x][T] == 0) m[x].erase(T);
			T--;
		}
		return r;
	}

}
void increment(int x, int T)
{
	long int t = get_right_degree(T);
	m[x][T]++;
	while (t<inf)
	{
		m[x][t]++;
		t = get_right_degree(t);
	}
}
void decrement(int x, int T)
{
	long int t = get_right_degree(T);
	m[x][T]--;
	while (t<inf)
	{
		m[x][t]--;
		t = get_right_degree(t);
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;

	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;

int main()
{
	map<int, map<int, int> > m;
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
		while (t < inf)
		{
			m[x][t]++;
			t += (t & -t);
		}
		else if (a == 2)
		while (t < inf)
		{
			m[x][t]--;
			t += (t & -t);
		}
		else if (a == 3)
		{
			for (r = 0; t > 0; t -= (t & -t))
				r += m[x][t];
			cout << r << endl;
		}
	}
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int n, x, a, t;
map<int, vector<int>> dec_sum;
const long int MAX_t =1000000000-1;
long int len = long int(10000*sqrt(10));
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	cin >> n;
	if (MAX_t%len != 0) size = int(MAX_t / len) + 1;
	else  size = int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}

}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int n, x, a, t;
map<int, vector<int>> dec_sum;
const long int MAX_t =1000000000-1;
long int len = long int(10000*sqrt(10));
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	cin >> n;
	if (MAX_t%len != 0) size = int(MAX_t / len) + 1;
	else  size = int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
int len = 1000000;
map<int, map<int, int> > m;

int get_ans(int x, int T)
{
	int r = 0, t;
	if (int((T-1) / len) != 0)
	{
		if (T%len != 0)
			r += m[x][T];
		t = int(T / len)*len;
		r += m[x][t];
	}
	else
	for (int i = 1; i <= T; ++i)
		r += m[x][i];

	return r;
}
void increment(int x, int T)
{
	m[x][T]++;
	int t = int(T / len)*len + len*int(T / len);
	while (t < inf)
	{
		m[x][t]++;
		t += len;
	}
}
void decrement(int x, int T)
{
	m[x][T]--;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]--;
		t += len;
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int n, x, a, t;
map<int, vector<int>> dec_sum;
const int MAX_t =1000000000-1;
int len = int(sqrt(MAX_t));
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	int len = int(sqrt(MAX_t));
	cin >> n;
	if (MAX_t%len != 0) size = int(MAX_t / len) + 1;
	else  size = int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;

struct Q
{
	int q;
	int t;
	int num;
};
void update(vector <map<int, int>> & times, int l, int r, int v, int t, int value, int q)
{
	if (!(t < l || t > r))
	{
		if (q == 1)
		{
			times[v][value]++;
		}
		else if (q == 2)
		{
			times[v][value]--;
		}

		if (l != r)
		{
			update(times, l, (l + r) / 2, 2 * v, t, value, q);
			update(times, (l + r) / 2 + 1, r, 2 * v + 1, t, value, q);
		}
	}
}
int count(vector<map <int, int>> &times, int l, int r, int v, int t0, int t, int value)
{
	int s1, s2;
	if (t < l || t0 > r)
	{
		return 0;
	}
	if (t0 <= l && t >= r)
	{
		return times[v][value];
	}
	s1 = count(times, l, (l + r) / 2, 2 * v, t0, t, value);
	s2 = count(times, (l + r) / 2 + 1, r, 2 * v + 1, t0, t, value);

	return s1 + s2;
}

void main()
{

	int n;
	cin >> n;
	vector<Q> a(n);
	vector< int > numbers(n);
	vector< int > times(n);

	for (int i = 1; i <= n; ++i)
	{
		cin >> a[i].q >> a[i].t >> a[i].num;
		numbers[i] = a[i].num;
		times[i] = a[i].t;
	}

	sort(numbers.begin(), numbers.end());
	numbers.erase(unique(numbers.begin(), numbers.end()), numbers.end());

	sort(times.begin(), times.end());
	times.erase(unique(times.begin(), times.end()), times.end());

	map <int, int> card;
	for (unsigned int i = 1; i < numbers.size(); ++i)
	{
		card[numbers[i]] = i;
	}
	for (int i = 1; i <= n; ++i)
	{
		a[i].num = card[a[i].num];
	}
	card.clear();

	for (unsigned int i = 1; i < times.size(); ++i)
	{
		card[times[i]] = i;
	}

	for (int i = 1; i <= n; ++i)
	{
		a[i].t = card[a[i].t];
	}
	int length = times.size() - 1;

	vector< map< int, int > > tree(4 * length);
	for (int i = 1; i <= n; ++i)
	{
		if (a[i].q != 3)
		{
			update(tree, 1, length, 1, a[i].t, a[i].num, a[i].q);
		}
		else
		{
			cout << count(tree, 1, length, 1, 1, a[i].t, a[i].num) << endl;
		}
	}
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int n, x, a, t;
map<int, vector<int>> dec_sum;
const long int MAX_t = 1e9-1;
int len = int(sqrt(MAX_t));
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	//cout << endl << sum << endl;
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			//cout << endl << TimeMachine[x][t] << endl;
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		//cout << endl << TimeMachine[x][Q] << endl;
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	int len = int(sqrt(MAX_t));
	cin >> n;
	if (MAX_t%len != 0) size = int(MAX_t / len) + 1;
	else  size = int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
//	system("Pause");
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
int len = 100;
map<int, map<int, int> > m;

int get_ans(int x, int T)
{
	int r = 0, t;
	if (int((T-1) / len) != 0)
	{
		if (T%len != 0)
			r += m[x][T];
		t = int(T / len)*len;
		r += m[x][t];
	}
	else
	for (int i = 1; i <= T; ++i)
		r += m[x][i];

	return r;
}
void increment(int x, int T)
{
	m[x][T]++;
	int t = int(T / len)*len + len*int(T / len);
	while (t < inf)
	{
		m[x][t]++;
		t += len;
	}
}
void decrement(int x, int T)
{
	m[x][T]--;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]--;
		t += len;
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(max_t / len);
	if (max_t%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if (T[i] % len != 0)
			for (int h = T[i]; h%len != 0; h--)
				ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}

}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(max_t / len);
	if (max_t%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if ((T[i] + 1) % len == 0)
				ans += Time_areas[int(T[i]/ len)][X[i]];
			else if (T[i] % len != 0)
			for (int h = len*int(T[i] / len); h<=T[i]; h++)
						ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int  x, a, t;
long int n;
map<int, vector<int>> dec_sum;
const long int MAX_t =1000000000-1;
long int len = long int(10000*3);
long int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	cin >> n;
	if (MAX_t%len != 0)
		size = long int(MAX_t / len) + 1;
	else  size =long int(MAX_t / len);

	for (long int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;

struct Q
{
	int q;
	int t;
	int num;
};
void update(vector <map<int, int>> & times, int l, int r, int v, int t, int value, int q)
{
	if (!(t < l || t > r))
	{
		if (q == 1)
		{
			times[v][value]++;
		}
		else if (q == 2)
		{
			times[v][value]--;
		}

		if (l != r)
		{
			update(times, l, (l + r) / 2, 2 * v, t, value, q);
			update(times, (l + r) / 2 + 1, r, 2 * v + 1, t, value, q);
		}
	}
}
int count(vector<map <int, int>> &times, int l, int r, int v, int t0, int t, int value)
{
	int s1, s2;
	if (t < l || t0 > r)
	{
		return 0;
	}
	if (t0 <= l && t >= r)
	{
		return times[v][value];
	}
	s1 = count(times, l, (l + r) / 2, 2 * v, t0, t, value);
	s2 = count(times, (l + r) / 2 + 1, r, 2 * v + 1, t0, t, value);

	return s1 + s2;
}

void main()
{

	int n,m;
	cin >> n;
	vector<Q> a(n);
	vector< int > numbers(n);
	vector< int > times(n);

	for (int i = 0; i < n; ++i)
	{
		cin >> a[i].q >> a[i].t >> a[i].num;
		numbers[i] = a[i].num;
		times[i] = a[i].t;
	}

	sort(numbers.begin(), numbers.end());
	numbers.erase(unique(numbers.begin(), numbers.end()), numbers.end());

	sort(times.begin(), times.end());
	times.erase(unique(times.begin(), times.end()), times.end());

	map <int, int> card;
	for (int i = 0; i < numbers.size(); ++i)
	{
		card[numbers[i]] = i;
	}
	for (int i = 0; i < n; ++i)
	{
		a[i].num = card[a[i].num];
	}
	card.clear();

	for (int i = 0; i < times.size(); ++i)
	{
		card[times[i]] = i;
	}

	for (int i = 0; i < n; ++i)
	{
		a[i].t = card[a[i].t];
	}
	card.clear();
	int length = times.size() - 1;

	vector< map< int, int > > tree(4 * length);
	for (int i = 0; i < n; ++i)
	{
		if (a[i].q != 3)
		{
			update(tree, 0, length, 1, a[i].t+1, a[i].num, a[i].q);
		}
		else
		{
			cout << count(tree, 0, length, 1, 1, a[i].t+1, a[i].num) << endl;
		}
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int n, x, a, t;
map<int, vector<int>> dec_sum;
const long int MAX_t =1000000000-1;
int len = int(sqrt(MAX_t));
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	//cout << endl << sum << endl;
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			//cout << endl << TimeMachine[x][t] << endl;
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		//cout << endl << TimeMachine[x][Q] << endl;
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <long int> M;
	int len = int(sqrt(MAX_t));
	cin >> n;
	if (MAX_t%len != 0) size = int(MAX_t / len) + 1;
	else  size = int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
int len = 100000;
map<int, map<int, int> > m;

int get_ans(int x, int T)
{
	int r = 0, t;
	if (int((T-1) / len) != 0)
	{
		if (T%len != 0)
			r += m[x][T];
		t = int(T / len)*len;
		r += m[x][t];
	}
	else
	for (int i = 1; i <= T; ++i)
		r += m[x][i];

	return r;
}
void increment(int x, int T)
{
	m[x][T]++;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]++;
		t += len;
	}
}
void decrement(int x, int T)
{
	m[x][T]--;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]--;
		t += len;
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(max_t / len);
	if (max_t%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if ((T[i] + 1) % len == 0)
				ans += Time_areas[int(T[i]/ len)][X[i]];
			else if (T[i] % len != 0)
			for (int h = len*int(T[i] / len); h<=T[i]; h++)
			if (TimeMachine[h].count(X[i])>0)
						ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;

int main()
{
	map<int, map<int, int> > m;
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
		while (t < inf) m[x][t]++, t += (t & -t);
		else if (a == 2)
		while (t < inf) m[x][t]--, t += (t & -t);
		else if (a == 3)
		{
			for (r = 0; t > 0; t -= (t & -t)) r += m[x][t];
			cout << r << endl;
		}
	}
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
int len = 10000;
map<int, map<int, int> > m;

int get_ans(int x, int T)
{
	int r = 0, t;
	if (int((T-1) / len) != 0)
	{
		if (T%len != 0)
			r += m[x][T];
		t = int(T / len)*len;
		r += m[x][t];
	}
	else
	for (int i = 1; i <= T; ++i)
		r += m[x][i];

	return r;
}
void increment(int x, int T)
{
	m[x][T]++;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]++;
		t += len;
	}
}
void decrement(int x, int T)
{
	m[x][T]--;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]--;
		t += len;
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}

}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(max_t / len);
	if (max_t%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if ((T[i] + 1) % len == 0)
				ans += Time_areas[int(T[i]/ len)][X[i]];
			else if (T[i] % len != 0)
			for (int h = int(T[i] / len); h<=T[i]; h++)
						ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}
}


#include <map>
#include <iostream>

using namespace std;

map<int, map<int, int>> TimeMachine;
int n, x, a, t;

void main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (a == 1)
				TimeMachine[x][t] += 1;
		if (a == 2)
				TimeMachine[x][t] -= 1;
		int q=0;
		if (a == 3)
		{
			while (t>0)
			{
				q += TimeMachine[x][t];
				t--;
			}
			cout << q << endl;
		}
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int  n, x, a, t;
map<int, vector<int>> dec_sum;
const int MAX_t =1000000000-1;
int len = int(10000*3);
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <int> M;
	cin >> n;
	if (MAX_t%len != 0)
		size = int(MAX_t / len) + 1;
	else  size =int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
using namespace std;

map<int, map<int, int>> TimeMachine;

void main()
{
	int n, a, t, x, max_t = 0;
	long int ans;
	cin >> n;

	vector<int> A, X, T;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		A.push_back(a);
		T.push_back(t-1);
		X.push_back(x);
		if (max_t < t) max_t = t;
	}
	int len = int (sqrtf(max_t));
	int count_times_area = int(max_t / len);
	if (max_t%len != 0) count_times_area++;
	vector<map<int, int>> Time_areas(count_times_area);

	for (int i = 0; i < n; ++i)
	{
		if (A[i] == 1)
		{
			TimeMachine[T[i]][X[i]] += 1;
			Time_areas[int(T[i] / len)][X[i]] += 1;
		}
		if (A[i] == 2)
		{
			TimeMachine[T[i]][X[i]] -= 1;
			Time_areas[int(T[i] / len)][X[i]] -= 1;
		}

		if (A[i] == 3)
		{
			ans = 0;
			for (int h = 0; h < int(T[i] / len); ++h)
				ans += Time_areas[h][X[i]];
			if (T[i] % len != 0)
			for (int h = T[i]; h%len != 0; h++)
				ans += TimeMachine[h][X[i]];
			cout << ans << endl;
		}
	}

}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
const int len = 2;
map<int, map<int, int> > m;

int get_right_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	if (y == t) return int(y*x);
	return int(y);
}
int get_left_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	return int(y/x);
}
int get_ans(int x, int T)
{
	int  t = get_left_degree(T);
	if (t*len == T)
		return m[x][t];
	else
		return m[x][t]+m[x][T];

}
void increment(int x, int T)
{
	long int t = get_right_degree(T);
	m[x][T]++;
	while (t<inf)
	{
		m[x][t]++;
		t = get_right_degree(t);
	}
}
void decrement(int x, int T)
{
	long int t = get_right_degree(T);
	m[x][T]--;
	while (t<inf)
	{
		m[x][t]--;
		t = get_right_degree(t);
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;

	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
	//system("Pause");
}


#include <map>
#include <iostream>
#include <vector>
#include <set>

using namespace std;

map<int, map<int, int>> TimeMachine;
int  n, x, a, t;
map<int, vector<short>> dec_sum;
const int MAX_t =1000000000-1;
int len = int(10000*3);
int size;

int sqrt_decomp()
{
	int r = t-1;
	int sum = 0;
	int  q, Q;
	if ((r + 1) % len == 0) q = 0;
	else q = 1;

	if (int(r / len) == 0)
	for (int i = 0; i <= r;++i)
		sum += TimeMachine[x][i];
	else
	for (int i = 0; i <= int(r / len) - q; ++i)
		sum += dec_sum[x][i];
	if (0 != int(r / len))
	{
		for (int t = r; t%len != 0; --t)
		{
			sum += TimeMachine[x][t];
			Q = t - 1;
		}
		sum += TimeMachine[x][Q];
	}
	return sum;
}

void main()
{
	set <int> M;
	cin >> n;
	if (MAX_t%len != 0)
		size = int(MAX_t / len) + 1;
	else  size =int(MAX_t / len);

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		if (M.find(x) == M.end())
		{
			M.insert(x);
			dec_sum[x].resize(size);
		}

		if (a == 1)
		{
			TimeMachine[x][t] += 1;
			dec_sum[x][int((t - 1) / len)] +=1;
		}
		if (a == 2)
		{
			TimeMachine[x][t] -= 1;
			dec_sum[x][int((t - 1) / len)] -= 1;
		}

		if (a == 3)
			cout << sqrt_decomp() << endl;

	}
	//system("Pause");
}


#include "stdafx.h"
#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
int len = 100000;
map<int, map<int, int> > m;

int get_ans(int x, int T)
{
	int r = 0, t;
	if (int((T-1) / len) != 0)
	{
		if (T%len != 0)
			r += m[x][T];
		t = int(T / len)*len;
		r += m[x][t];
	}
	else
	for (int i = 1; i <= T; ++i)
		r += m[x][i];

	return r;
}
void increment(int x, int T)
{
	m[x][T]++;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]++;
		t += len;
	}
}
void decrement(int x, int T)
{
	m[x][T]--;
	int t = int(T / len)*len + len;
	while (t < inf)
	{
		m[x][t]--;
		t += len;
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}

}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;
const int len = 2;
map<int, map<int, int> > m;

int get_right_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	if (y == t) return int(y*x);
	return int(y);
}
int get_left_degree(int t, int x = len)
{
	long int y = 1;
	while (y<t)
		y *= x;
	return int(y/x);
}
int get_ans(int x, int T)
{
	int  t = get_left_degree(T);
	if (t*len == T)
		return m[x][T];
	else
	{
		int r = 0;
		while (T >= t)
		{
			r += m[x][T];
			if (m[x][T] == 0) m[x].erase(T);
			T--;
		}
		return r;
	}

}
void increment(int x, int T)
{
	long int t = get_right_degree(T);
	m[x][T]++;
	while (t<inf)
	{
		m[x][t]++;
		t = get_right_degree(t);
	}
}
void decrement(int x, int T)
{
	long int t = get_right_degree(T);
	m[x][T]--;
	while (t<inf)
	{
		m[x][t]--;
		t = get_right_degree(t);
	}
}

int main()
{
	int n, a, t, x, r;
	cin >> n;

	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
			increment(x, t);
		else if (a == 2)
			decrement(x, t);
		else if (a == 3)
			cout << get_ans(x, t) << endl;
	}
}


#include <iostream>
#include <iomanip>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;

struct T
{
   int v, t, x;
   T( int v, int t, int x) : v(v), t(t), x(x) {}
};

int sum ( vector<int> &t, int r)
{
	int result = 0;
	for (; r >= 0; r = (r & (r+1)) - 1)
		result += t[r];
	return result;
}

void inc ( vector<int> &t, int i, int delta)
{
	for (; i < t.size(); i = (i | (i+1)))
		t[i] += delta;
}

vector<T> a;

map<int, int> val_to_num;

vector<vector<int>> t;

vector<map<int, int>> b;

int main()
{
#ifdef LOCAL
   freopen("input.txt", "rt", stdin);
   freopen("output.txt", "wt", stdout);
#endif
   int n;
   scanf("%d", &n);
   for( int i = 0; i < n; i++ )
   {
      int v, t, x;
      scanf("%d %d %d", &v, &t, &x);
      a.push_back( T(v, t, x) );
      val_to_num.insert( make_pair( a[i].x, 0 ) );
   }
   {
      int k = 0;
      for( auto iter = val_to_num.begin(); iter != val_to_num.end(); iter++ )
         iter->second = k++;
   }
   int cnt = val_to_num.size();

   t.assign( cnt, vector<int>() );
   b.assign( cnt, map<int, int>() );

   for( int i = 0; i < n; i++ )
   {
      T k = a[i];
      b[val_to_num[a[i].x]][a[i].t] = 0;
   }
   for( int i = 0; i < cnt; i++ )
   {
      int k = 0;
      for( auto iter = b[i].begin(); iter != b[i].end(); iter++ )
         iter->second = k++;
      t[i].assign( k, 0 );
   }
   for( int i = 0; i < n; i++ )
   {
      T k = a[i];
      int x_ = val_to_num[a[i].x];
      int t_ = b[x_][a[i].t];
      if( a[i].v == 1 )
      {
         inc( t[x_], t_, 1 );
      }
      else if( a[i].v == 2 )
         inc( t[x_], t_, -1 );
      else if( a[i].v == 3 )
         cout << sum( t[x_], t_ ) << endl;
   }
}


#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <cmath>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <queue>
#include <stack>
#include <bitset>
#define y1 y11
#define fs first
#define sc second
#define mp make_pair
#define pb push_back
#define mt make_tuple
#define NAME ""

using namespace std;

typedef long long ll;
typedef long double ld;

const ld PI = acos(-1.0);

const int MAXN = 2000001;

struct node
{
	node *l;
	node *r;
	int val;
	int prior;
	int key;
	int sum;
};

inline int gs(node* t)
{
	return t?(t->sum):0;
}

node* newnode(int tm, int vl)
{
	node* nn = new node();
	nn->l = nn->r = NULL;
	nn->prior = (rand() << 16) + rand();
	nn->sum = nn->val = vl;
	nn->key = tm;
	return nn;
}

typedef node* pnode;

inline void upd(pnode t)
{
	t->sum = t->val + gs(t->l) + gs(t->r);
}

void split(pnode t, pnode& l, pnode& r, int k)
{
	if (!t)
	{
		l = r = NULL;
		return;
	}
	if (t->key > k)
	{
		r = t;
		split(t->l, l, r->l, k);
	}
	else
	{
		l = t;
		split(t->r, l->r, r, k);
	}
	upd(t);
}

void merge(pnode& t, pnode l, pnode r)
{
	if (!l)
	{
		t = r;
		return;
	}
	if (!r)
	{
		t = l;
		return;
	}
	if (l->prior > r->prior)
	{
		t = l;
		merge(t->r, l->r, r);
	}
	else
	{
		t = r;
		merge(t->l, l, r->l);
	}
	upd(t);
}

int xs[MAXN];
int a[MAXN], x[MAXN], t[MAXN];
pnode root[MAXN];
pnode n1, n2, n3, n4;
int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	ios_base::sync_with_stdio(0);
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d%d%d", &a[i], &t[i], &x[i]);
		xs[i] = x[i];
	}
	sort(xs, xs + n);
	int xc = unique(xs, xs + n) - xs;
	for (int i = 0; i < xc; i++) root[i] = NULL;
	for (int i = 0; i < n; i++)
	{
		x[i] = lower_bound(xs, xs + xc, x[i]) - xs;
		split(root[x[i]], n1, n2, t[i]);
		if (a[i] == 3)
		{
			printf("%d\n", gs(n1));
			merge(root[x[i]], n1, n2);
		}
		else
		{
			n4 = newnode(t[i], 1);
			if (a[i] == 2) n4->val = n4->sum = -1;
			merge(n3, n1, n4);
			merge(root[x[i]], n3, n2);
		}
	}
	return 0;
}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;

int main()
{
	map<int, map<int, int> > m;
	int n, a, t, x, y, answer;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
		while (t < inf)
		{
			m[x][t]++;
			t += (t & -t);
		}
		 if (a == 2)
		while (t < inf)
		{
			m[x][t]--;
			t += (t & -t);
		}
		 if (a == 3)
		{
			for (answer = 0; t > 0; t -= (t & -t))
			    answer += m[x][t];
			cout << answer << endl;
		}

		}

	}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;

int main()
{
	map<int, map<int, int> > m;
	int n, a, t, x, answer;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
		while (t < inf)
		{
			m[x][t]++;
			t += (t & -t);
		}
		 if (a == 2)
		while (t < inf)
		{
			m[x][t]--;
			t += (t & -t);
		}
		 if (a == 3)
		{
			for (answer = 0; t > 0; t -= (t & -t))
			    answer += m[x][t];
			cout << answer << endl;
		}

		}

	}


#include <iostream>
#include <map>

using namespace std;

const int inf = 1e9 + 1;

int main()
{
	map<int, map<int, int> > m;
	int n, a, t, x, answer;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a >> t >> x;
		if (a == 1)
		while (t < inf)
		{
			m[x][t]++;
			t += (t & -t);
		}
		 if (a == 2)
		while (t < inf)
		{
			m[x][t]--;
			t += (t & -t);
		}
		 if (a == 3)
		{
			for (answer = 0; t > 0; t -= (t & -t))
			    answer += m[x][t];
		}
				cout << answer << endl;
		}

	}


#include <iostream>
#include <set>
#include <map>
#include <vector>

using namespace std;

struct numberData
{
	map <int, set <int>> plus;
	map <int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 1e4;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].plus.find(i) != nums[x].plus.end())
		mi += nums[x].plus[i].size();

	iter = nums[x].plus[t / decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}

	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].minus.find(i) != nums[x].minus.end())
		mi += nums[x].minus[i].size();

	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberData
{
	map< int, set <int>> plus;
	map< int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 1e5;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
		pl += nums[x].plus[i].size();
	iter = nums[x].plus[t/decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}
	for (int i = 0; i < t / decRate; ++i)
		mi += nums[x].minus[i].size();
	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int INF = 1e9;
	map<int, map<int, int> > decomp;
	int n;
	int a;
	int	t;
	int x;
	int sum;

	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		switch (a)
		{
		case 1:
			while (t < INF)
			{
				++decomp[x][t];
				t += (t & -t);
			}
			break;
		case 2:
			while (t < INF)
			{
				--decomp[x][t];
				t += (t & -t);
			}
			break;
		case 3:
			for (sum = 0; t > 0; t -= (t & -t))
				sum += decomp[x][t];
			cout << sum << endl;
			break;
		}
	}
		return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int INF = 1e9;
	map<int, map<int, int> > decomp;
	int n;
	int a;
	int	t;
	int x;
	int sum;

	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		switch (a)
		{
		case 1:
			while (t < INF)
			{
				++decomp[x][t];
				t += (t & -t);
			}
			break;
		case 2:
			while (t < INF)
			{
				--decomp[x][t];
				t += (t & -t);
			}
			break;
		case 3:
			sum = 0;
			while (t > 0)
			{
				sum += decomp[x][t];
				t -= (t & -t));
			}
			cout << sum << endl;
			break;
		}
	}
		return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberDecData
{
	map <int,int> plus;
	map <int,int> minus;
};

struct numberData
{
	set <int> plus;
	set <int> minus;
};

map <int, numberData> nums;
map <int, numberDecData> numsDec;
int n;
int decRate = 1000;
map <int, set <int>> decList;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;

	for (set <int>::iterator i = decList[x].begin(); *i < t / decRate && i != decList[x].end(); ++i)
	{
		pl += numsDec[x].plus[*i];
		mi += numsDec[x].minus[*i];
	}

	set <int>::iterator iter;

	iter = nums[x].plus.begin();
	while (iter != nums[x].plus.end() && *iter < t)
	{
		++pl;
		++iter;
	}

	iter = nums[x].minus.begin();
	while (iter != nums[x].minus.end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
			{
				numsDec[x].plus[t/decRate]++;
				nums[x].plus.insert(t);
			}
			else
			{
				numsDec[x].minus[t/decRate]++;
				nums[x].minus.insert(t);
			}
			if (!decList[x].count(t / decRate))
				decList[x].insert(t / decRate);
		}
		else
		{
			cout << getSum(x, t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

struct command
{
	int a;
	int x;
};

int main()
{
	int n;
	int sqrtOfn;
	int a;
	int t;
	int x;
	cin >> n;
	sqrtOfn = floor(sqrt((double)n));
	map <int, command> com;
	map <int, map <int, int>> countNumsDec;				// Количества экземпляров по блокам декомпозиции <<число, количество экземпляров>, Время  >
	int s;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;
		if (a != 3)
		{
			com[t].a = a;
			com[t].x = x;
		}

		switch (a)
		{
		case 1:
			countNumsDec[x][floor((double)t / sqrtOfn)]++;
			break;
		case 2:
			countNumsDec[x][floor((double)t / sqrtOfn)]--;
			break;
		case 3:
			s = 0;
			for (int j = 0; j < floor((double)t / sqrtOfn); ++j)
				s += countNumsDec[x][j];
			for (int j = floor((double)t / sqrtOfn)*sqrtOfn; j <= t; ++j)
			if (com[j].x == x)
				switch (com[j].a)
			{
				case 1: ++s;
					break;
				case 2: --s;
					break;
			}
			cout << s << '\n';
		}

	}

	return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberData
{
	map< int, set <int>> plus;
	map< int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 1000;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
		pl += nums[x].plus[i].size();
	iter = nums[x].plus[t/decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}
	for (int i = 0; i < t / decRate; ++i)
		mi += nums[x].minus[i].size();
	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int INF = 1e9;
	map<int, map<int, int> > decomp;
	int n;
	int a;
	int	t;
	int x;
	int sum;

	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		switch (a)
		{
		case 1:
			while (t < INF)
			{
				++decomp[x][t];
				t += (t & -t);
			}
			break;
		case 2:
			while (t < INF)
			{
				--decomp[x][t];
				t += (t & -t);
			}
			break;
		case 3:
			sum = 0;
			while (t > 0)
			{
				sum += decomp[x][t];
				t -= (t & -t);
			}
			cout << sum << endl;
			break;
		}
	}
		return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int n;
	int a;
	int t;
	int sqrtOft = floor(sqrt(1e9));
	map <int, map<int, int>> com;
	map <int, map<int, int>> decCom;
	int x;
	int s;
	cin >> n;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;

		switch (a)
		{
		case 1:
			++com[x][t];
			++decCom[x][t / sqrtOft];
			break;
		case 2:
			--com[x][t];
			--decCom[x][t / sqrtOft];
			break;
		case 3:
			s = 0;
			for (int j = 0; i < t / sqrtOft; ++j)
				s += decCom[x][j];
			for (int j = t / sqrtOft; j < t; ++j)
				s += com[x][j];
			cout << s << '\n';
			break;
		}

	}
	return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberDecData
{
	map< int, set <int>> plus;
	map< int, set <int>> minus;
};

struct numberData
{
	set <int> plus;
	set <int> minus;
};

map <int,numberData> nums;
map <int, numberDecData> numsDec;
int n;
int decRate = 1000;
map <int, set <int>> decList;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;

	for (set <int>::iterator i = decList[x].begin(); *i < t / decRate && i != decList[x].end(); ++i)
	{
		pl += numsDec[x].plus[*i].size();
		mi += numsDec[x].minus[*i].size();
	}

	set <int>::iterator iter;

	iter = nums[x].plus.begin();
	while (iter != nums[x].plus.end() && *iter < t)
	{
		++pl;
		++iter;
	}

	iter = nums[x].minus.begin();
	while (iter != nums[x].minus.end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
			{
				numsDec[x].plus[t / decRate].insert(t);
				nums[x].plus.insert(t);
			}
			else
			{
				numsDec[x].minus[t / decRate].insert(t);
				nums[x].minus.insert(t);
			}
			if (!decList[x].count(t / decRate))
				decList[x].insert(t / decRate);
		}
		else
		{
			cout << getSum(x, t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int INF = 1e9;
	map<int, map<int, int> > tree;
	int n;
	int a;
	int	t;
	int x;
	int sum;

	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		switch (a)
		{
		case 1:
			while (t < INF)
			{
				++tree[x][t];
				t = t | (t+1);
			}
			break;
		case 2:
			while (t < INF)
			{
				--tree[x][t];
				t = t | (t+1);
			}
			break;
		case 3:
			sum = 0;
			while (t > 0)
			{
				sum += tree[x][t];
				t = (t & (t+1)-1);
			}
			cout << sum << endl;
			break;
		}
	}
		return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <vector>

using namespace std;

struct numberData
{
	map <int, set <int>> plus;
	map <int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 1000;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].plus.find(i) != nums[x].plus.end())
		mi += nums[x].plus[i].size();

	iter = nums[x].plus[t / decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}

	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].minus.find(i) != nums[x].minus.end())
		mi += nums[x].minus[i].size();

	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberData
{
	map< int, set <int>> plus;
	map< int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 100;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
		pl += nums[x].plus[i].size();
	iter = nums[x].plus[t/decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}
	for (int i = 0; i < t / decRate; ++i)
		mi += nums[x].minus[i].size();
	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

struct command
{
	int a;
	int x;
};

int main()
{
	int n;
	int sqrtOfn;
	int a;
	int t;
	int x;
	cin >> n;
	sqrtOfn = floor(sqrt((double)n));
	map <int, command> com;
	map <int, map <int, int>> countNumsDec;				// Количества экземпляров по блокам декомпозиции <Время , <число, количество экземпляров> >
	int s;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;
		if (a != 3)
		{
			com[t].a = a;
			com[t].x = x;
		}

		switch (a)
		{
		case 1:
			countNumsDec[floor((double)t / sqrtOfn)][x]++;
			break;
		case 2:
			countNumsDec[floor((double)t / sqrtOfn)][x]--;
			break;
		case 3:
			s = 0;
			for (int j = 0; j < floor((double)t / sqrtOfn); ++j)
				s += countNumsDec[j][x];
			for (int j = floor((double)t / sqrtOfn)*sqrtOfn; j <= t; ++j)
			if (com[j].x == x)
				switch (com[j].a)
			{
				case 1: ++s;
					break;
				case 2: --s;
					break;
			}
			cout << s << '\n';
		}

	}

	return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberData
{
	set <int> plus;
	set <int> minus;
};

map <int, numberData> nums;
int n;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	iter = nums[x].plus.begin();
	while (iter != nums[x].plus.end() && *iter < t)
	{
		++pl;
		++iter;
	}
	iter = nums[x].minus.begin();
	while (iter != nums[x].minus.end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus.insert(t);
			else
				nums[x].minus.insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int n;
	int sqrtOfn;
	int a;
	int t;
	int x;
	cin >> n;
	sqrtOfn = floor(sqrt((double)n));
	map <int, map<int,int>> countNums;					// <Время , <число, количество экземпляров> >
	//map <int, map <int, int>> countNumsDec;				// Количества экземпляров по блокам декомпозиции
	int s;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;

		switch (a)
		{
		case 1:
			countNums[t][x]++;
			//countNumsDec[floor((double)t/sqrtOfn)][x]++;
			break;
		case 2:
			countNums[t][x]--;
			//countNumsDec[floor((double)t / sqrtOfn)][x]--;
			break;
		case 3:
			s = 0;
			//for (int j = 0; j < floor((double)t / sqrtOfn); ++j)
			//	s += countNumsDec[j][x];
			for (int j = 0; j <= t; ++j)
				s += countNums[j][x];
			cout << s << '\n';
		}

	}
	return 0;
}


#include <iostream>
#include <set>
#include <map>

using namespace std;

struct numberDecData
{
	set <int> plus;
	set <int> minus;
};

struct numberData
{
	set <int> plus;
	set <int> minus;
};

map <int, numberData> nums;
map <int, numberDecData> numsDec;
int n;
int decRate = 1000;
map <int, set <int>> decList;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;

	for (set <int>::iterator i = decList[x].begin(); *i < t / decRate && i != decList[x].end(); ++i)
	{
		pl += numsDec[x].plus[*i];
		mi += numsDec[x].minus[*i];
	}

	set <int>::iterator iter;

	iter = nums[x].plus.begin();
	while (iter != nums[x].plus.end() && *iter < t)
	{
		++pl;
		++iter;
	}

	iter = nums[x].minus.begin();
	while (iter != nums[x].minus.end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
			{
				numsDec[x].plus[t/decRate]++;
				nums[x].plus.insert(t);
			}
			else
			{
				numsDec[x].minus[t/decRate]++;
				nums[x].minus.insert(t);
			}
			if (!decList[x].count(t / decRate))
				decList[x].insert(t / decRate);
		}
		else
		{
			cout << getSum(x, t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int n;
	int sqrtOfn;
	int a;
	int t;
	int x;
	cin >> n;
	sqrtOfn = floor(sqrt((double)n));
	map <int,map<int,int>> countNums;					// <Время , <число, количество экземпляров> >
	map <int, map <int, int>> countNumsDec;				// Количества экземпляров по блокам декомпозиции
	int s;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;

		switch (a)
		{
		case 1:
			countNums[t][x]++;
			countNumsDec[floor((double)t/sqrtOfn)][x]++;
			break;
		case 2:
			countNums[t][x]--;
			countNumsDec[floor((double)t / sqrtOfn)][x]--;
			break;
		case 3:
			s = 0;
			for (int j = 0; j < floor((double)t / sqrtOfn); ++j)
				s += countNumsDec[j][x];
			for (int j = floor((double)t / sqrtOfn)*sqrtOfn; j <= t; ++j)
				s += countNums[j][x];
			cout << s << '\n';
		}

	}
	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int n;
	int sqrtOfn;
	int a;
	int t;
	int x;
	cin >> n;
	sqrtOfn = floor(sqrt((double)n));
	map <int,map<int,int>> countNums;					// <Время , <число, количество экземпляров> >
	map <int, map <int, int>> countNumsDec;				// Количества экземпляров по блокам декомпозиции
	int s;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;

		switch (a)
		{
		case 1:
			countNums[t][x]++;
			countNumsDec[floor(t/sqrtOfn)][x]++;
			break;
		case 2:
			countNums[t][x]--;
			countNumsDec[floor(t / sqrtOfn)][x]--;
			break;
		case 3:
			s = 0;
			for (int j = 0; j < floor(t / sqrtOfn); ++j)
				s += countNumsDec[j][x];
			for (int j = floor(t / sqrtOfn)*sqrtOfn; j <= t; ++j)
				s += countNums[j][x];
			cout << s << '\n';
		}

	}
	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int INF = 1e9;
	map<int, map<int, int> > tree;
	int n;
	int a;
	int	t;
	int x;
	int sum;

	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		switch (a)
		{
		case 1:
			while (t < INF)
			{
				++tree[x][t];
				t = t | (t+1);
			}
			break;
		case 2:
			while (t < INF)
			{
				--tree[x][t];
				t = (t | (t+1);
			}
			break;
		case 3:
			sum = 0;
			while (t > 0)
			{
				sum += tree[x][t];
				t = (t & (t+1))-1;
			}
			cout << sum << endl;
			break;
		}
	}
		return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int n;
	int a;
	int t;
	int sqrtOft = floor(sqrt(1e9));
	map <int, map<int, int>> com;
	map <int, map<int, int>> decCom;
	int x;
	int s;
	cin >> n;

	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		t--;

		switch (a)
		{
		case 1:
			++com[t][x];
			++decCom[t / sqrtOft][x];
			break;
		case 2:
			--com[t][x];
			--decCom[t / sqrtOft][x];
			break;
		case 3:
			s = 0;
			for (int j = 0; i < t / sqrtOft; ++j)
				s += decCom[j][x];
			for (int j = t / sqrtOft; j < t; ++j)
				s += com[j][x];
			cout << s << '\n';
			break;
		}

	}
	return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <vector>

using namespace std;

struct numberData
{
	map <int, set <int>> plus;
	map <int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 1000;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].plus.count(i))
		mi += nums[x].plus[i].size();

	iter = nums[x].plus[t / decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}

	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].minus.count(i))
		mi += nums[x].minus[i].size();

	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <vector>

using namespace std;

struct numberData
{
	map <int, set <int>> plus;
	map <int, set <int>> minus;
};

map <int, numberData> nums;
int n;
int decRate = 1e5;

int getSum(int x, int t)
{
	int pl = 0;
	int mi = 0;
	set <int>::iterator iter;
	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].plus.find(i) != nums[x].plus.end())
		mi += nums[x].plus[i].size();

	iter = nums[x].plus[t / decRate].begin();
	while (iter != nums[x].plus[t / decRate].end() && *iter < t)
	{
		++pl;
		++iter;
	}

	for (int i = 0; i < t / decRate; ++i)
	if (nums[x].minus.find(i) != nums[x].minus.end())
		mi += nums[x].minus[i].size();

	iter = nums[x].minus[t / decRate].begin();
	while (iter != nums[x].minus[t / decRate].end() && *iter < t)
	{
		++mi;
		++iter;
	}

	return pl - mi;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int a, t, x;
		cin >> a >> t >> x;
		--t;
		if (a != 3)
		{
			if (a == 1)
				nums[x].plus[t/decRate].insert(t);
			else
				nums[x].minus[t/decRate].insert(t);
		}
		else
		{
			cout << getSum(x,t) << '\n';
		}
	}

	return 0;
}


#include <iostream>
#include <map>

using namespace std;

int main()
{
	int INF = 1e9;
	map<int, map<int, int> > tree;
	int n;
	int a;
	int	t;
	int x;
	int sum;

	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> a >> t >> x;
		switch (a)
		{
		case 1:
			while (t < INF)
			{
				++tree[x][t];
				t = t | (t+1);
			}
			break;
		case 2:
			while (t < INF)
			{
				--tree[x][t];
				t = t | (t+1);
			}
			break;
		case 3:
			sum = 0;
			while (t > 0)
			{
				sum += tree[x][t];
				t = (t & (t+1))-1;
			}
			cout << sum << endl;
			break;
		}
	}
		return 0;
}


from bisect import *
u, v = {}, {}
for q in range(int(input())):
    a, t, x = map(int, input().split())
    if x not in u: u[x], v[x] = [], []
    if a < 3: insort([v, u][-a][x], t)
    else: print(bisect(u[x], t) - bisect(v[x], t))


from bisect import *
d = {}
for q in range(int(input())):
    a, t, x = map(int, input().split())
    d[x] = p = d.get(x, [])
    i = bisect(p, t)
    if a == 1: p.insert(t, i)
    elif a == 2: p.pop(i - 1)
    else: print(i)


from bisect import *
d = [{}, {}]
i = [0, 0]
for q in range(int(input())):
    a, t, x = map(int, input().split())
    for k in [0, 1]:
        d[k][x] = d[k].get(x, [])
        i[k] = bisect(d[k][x], t)
    if a < 3: d[-a][x].insert(i[-a], t)
    else: print(i[1] - i[0])


#E.py
import sys
#sys.stdin = open('E.in')

from bisect import bisect, bisect_left
from collections import defaultdict

def main():
    num_dict = defaultdict(list)
    n = int(raw_input())
    for i in range(n):
        a, t, x = [int(k) for k in raw_input().split()]
        if a == 1:
            #add
            idx = bisect(num_dict[x], t)
            num_dict[x].insert(idx, t)
        elif a == 2:
            # del
            idx = bisect(num_dict[x], t)
            #print num_dict[x], t, idx
            if idx > 0:
                del num_dict[x][idx-1]
            else:
                pass
        else:
            idx = bisect(num_dict[x], t)
            print idx
main()


#E.py
import sys
#sys.stdin = open('E.in')

from bisect import bisect, bisect_left
from collections import defaultdict

def main():
    add_dict = defaultdict(list)
    del_dict = defaultdict(list)

    n = int(raw_input())
    for i in range(n):
        a, t, x = [int(k) for k in raw_input().split()]
        if a == 1:
            #add
            idx = bisect(add_dict[x], t)
            add_dict[x].insert(idx, t)
        elif a == 2:
            # del
            idx = bisect(del_dict[x], t)
            del_dict[x].insert(idx, t)

        else:
            idx_add = bisect(add_dict[x], t)
            idx_del = bisect(del_dict[x], t)
            print idx_add - idx_del
main()


#E.py
import sys
#sys.stdin = open('E.in')

from bisect import bisect, bisect_left
from collections import defaultdict

def main():
    num_dict = defaultdict(list)
    n = int(raw_input())
    for i in range(n):
        a, t, x = [int(k) for k in raw_input().split()]
        if a == 1:
            #add
            idx = bisect(num_dict[x], t)
            num_dict[x].insert(idx, t)
        elif a == 2:
            # del
            idx = bisect(num_dict[x], t)
            #print num_dict[x], t, idx
            if idx > 0:
                del num_dict[x][idx-1]
            else:
                pass
        else:
            idx = bisect_left(num_dict[x], t)
            print idx
main()