This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
#ifdef DEBUG
	#define D(x...) printf(x)
#else	
	#define D(x...)
#endif
typedef long long ll;
int n, m, g[30010], isbelow[30010], num1[30010], num2[30010];
vector<int> group[30010], ag[30010], bg[30010];
ll x[30010], y[30010];
pair<ll, ll> s, e;
ll cross(pair<ll, ll> a, pair<ll, ll> b, pair<ll, ll> c)
{
	a.first -= c.first, b.first -= c.first;
	a.second -= c.second, b.second -= c.second;
	return a.first*b.second - a.second*b.first;
}
void findids(bool rev, pair<ll, ll> s, pair<ll, ll> e, int* num)
{
	// separate into left and right
	vector<pair<pair<ll, ll>, int> > below;
	for (int i = 0; i < n; i++)
	{
		pair<ll, ll> other = { x[i] + 2ll*(s.first-x[i]), y[i] + 2ll*(s.second-y[i]) };
	//	D("%lld %lld\n", other.first, other.second);
		if (cross(s, {x[i], y[i]}, e) < 0) 
		{
			if (rev) below.push_back({other, i});
			else isbelow[i] = 1, below.push_back({{ x[i], y[i] }, i });
		}
		else
		{
			if (!rev) below.push_back({other, i});
			else isbelow[i] = 1, below.push_back({{ x[i], y[i] }, i });
		}
//		D("%d: isbelow %d\n", i, isbelow[i]);
	}
	sort(below.begin(), below.end(), [s](const pair<pair<ll, ll>, int> &a, const pair<pair<ll, ll>, int> &b)
	{
		return cross(a.first, b.first, s) < 0;
	});
	if (rev) reverse(below.begin(), below.end());
//	for (auto b : below) D("%d ", b.second);
//	D(" -- below\n");
	for (int i = 0; i < (int)below.size(); i++) num[below[i].second] = i;
}
struct Node
{
	int val, left, right;
};
int upto;
Node rangetree[30010*40];
void update(int node, int curr, int oldcurr, int cstart = 0, int cend = 30010)
{
	rangetree[curr].val = rangetree[oldcurr].val;
	if (cstart == cend)
	{
		rangetree[curr].val++;
		return;
	}
	int mid = (cstart+cend)/2;
	if (node <= mid)
	{
		rangetree[curr].left = ++upto;
		rangetree[curr].right = rangetree[oldcurr].right;
		update(node, rangetree[curr].left, rangetree[oldcurr].left, cstart, mid);
	}
	else
	{
		rangetree[curr].right = ++upto;
		rangetree[curr].left = rangetree[oldcurr].left;
		update(node, rangetree[curr].right, rangetree[oldcurr].right, mid+1, cend);
	}
	rangetree[curr].val = rangetree[rangetree[curr].left].val + rangetree[rangetree[curr].right].val;
}
int query(int s, int e, int curr, int cstart = 0, int cend = 30010)
{
	if (s <= cstart && cend <= e) return rangetree[curr].val;
	int mid = (cstart+cend)/2;
	if (e <= mid) return query(s, e, rangetree[curr].left, cstart, mid);
	else if (s > mid) return query(s, e, rangetree[curr].right, mid+1, cend);
	else return query(s, e, rangetree[curr].left, cstart, mid) + query(s, e, rangetree[curr].right, mid+1, cend);
}
int root[30010];
int aminlower(vector<int>&v, int x, int y, int l = 0)
{
	if (v.empty()) return 0;
	if (x < num1[v[0]]) return 0;
	int s = 0;
	int e = v.size()-1;
	while (s < e)
	{
		int m = (s+e+1)/2;
		if (num1[v[m]] > x) e = m-1;
		else s = m;
	}
	return query(l, y, root[v[s]]);
}
int aminupper(vector<int> &v, int x, int y)
{
	return aminlower(v, 1e9, 30010, y) - aminlower(v, x-1, 30010, y);
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i++)
	{
		scanf("%lld%lld%d", &x[i], &y[i], &g[i]);
		group[g[i]].push_back(i);
	}
	scanf("%lld%lld%lld%lld", &s.first, &s.second, &e.first, &e.second);
	findids(0, e, s, num1);
	findids(1, s, e, num2);
	for (int i = 1; i <= m; i++)
	{
		for (auto a : group[i])
		{
			if (isbelow[a]) bg[i].push_back(a);
			else ag[i].push_back(a);
		}
		sort(bg[i].begin(), bg[i].end(), [](const int &a, const int &b) { return num1[a] < num1[b]; });
		sort(ag[i].begin(), ag[i].end(), [](const int &a, const int &b) { return num1[a] < num1[b]; });
		int r = 0;
		for (auto a : ag[i])
		{
			root[a] = ++upto;
			update(num2[a], root[a], r);
			r = root[a];
		}
		r = 0;
		for (auto a : bg[i])
		{
			root[a] = ++upto;
			update(num2[a], root[a], r);
			r = root[a];
		}
	}
	int q;
	scanf("%d", &q);
	for (int query = 0; query < q; query++)
	{
		int i, j;
		scanf("%d%d", &i, &j);
		ll ans = 0;
		if (group[i].size() < group[j].size())
		{	
			for (auto a : group[i])
			{
				D("checking %d\n", a);
				ans += aminupper(bg[j], num1[a], num2[a]);
				ans += aminlower(ag[j], num1[a], num2[a]);
			}
		}
		else
		{
			for (auto a : group[j])
			{
				D("checking %d\n", a);
				if (isbelow[a])
				{
					ans += aminlower(bg[i], num1[a], num2[a]);
					ans += aminlower(ag[i], num1[a], num2[a]);
				}
				else
				{
					ans += aminupper(bg[i], num1[a], num2[a]);
					ans += aminupper(ag[i], num1[a], num2[a]);
				}
			}
		}
		printf("%lld\n", ans);
	}
}
Compilation message (stderr)
dragon2.cpp: In function 'int main()':
dragon2.cpp:106:7: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%d%d", &n, &m);
  ~~~~~^~~~~~~~~~~~~~~~
dragon2.cpp:109:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%lld%lld%d", &x[i], &y[i], &g[i]);
   ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dragon2.cpp:112:7: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%lld%lld%lld%lld", &s.first, &s.second, &e.first, &e.second);
  ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dragon2.cpp:140:7: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%d", &q);
  ~~~~~^~~~~~~~~~
dragon2.cpp:144:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d%d", &i, &j);
   ~~~~~^~~~~~~~~~~~~~~~| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |