VEXOBEN
Vexoben
Aug 16, 2018
It takes 4 minutes to read this article.

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=5016

题解

一个小小的套路,稍微记一下。

考虑的离线下来使用莫队。

询问有四个端点非常不好处理,那就前缀差分一下。

只需求 (get(1,r1)-get(1,l1-1))*(get(1,r2)-get(1,l2-1))

一个询问拆成四个,然后跑莫队即可。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 5e4 + 10;

int n, Q, siz, a[N];
LL res[N << 2] ,num[2][N];
struct Query {
	int l, r, num, block;
	bool operator < (const Query &b) const {
		if (block != b.block) return block < b.block;
		else return r < b.r;
	}
}q[N << 2];

int main(void) {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	scanf("%d", &Q);
	siz = sqrt(Q * 4) + 1;
	for (int i = 1; i <= Q; ++i) {
		int l1, r1, l2, r2;
		scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
		q[i * 4 - 3] = (Query) {r1, r2};
		q[i * 4 - 2] = (Query) {l1 - 1, l2 - 1};
		q[i * 4 - 1] = (Query) {l1 - 1, r2};
		q[i * 4] = (Query) {r1, l2 - 1};
	}
	for (int i = 1; i <= Q * 4; ++i) {
		if (q[i].l > q[i].r) swap(q[i].l, q[i].r);
		q[i].num = i; q[i].block = q[i].l / siz;
	}
	sort(q + 1, q + Q * 4 +1);
	int l = 1, r = 1; LL ans = 1;
	num[0][a[1]] = num[1][a[1]] = 1;
	for (int i = 1; i <= Q * 4; ++i) {
		if (q[i].l == 0) continue;
		while (l < q[i].l) ++l, ++num[0][a[l]], ans += num[1][a[l]];
		while (l > q[i].l) --num[0][a[l]], ans -= num[1][a[l]], --l;
		while (r < q[i].r) ++r, ++num[1][a[r]], ans += num[0][a[r]];
		while (r > q[i].r) --num[1][a[r]], ans -= num[0][a[r]], --r;
		res[q[i].num] = ans;
	}
	for (int i = 1; i <= Q; ++i) {
		ans = res[i * 4 - 3] + res[i * 4 - 2] - res[i * 4 - 1] - res[i * 4];
		printf("%lld\n", ans);
	}
	return 0;
}