题目描述
给你一个长度为 (N) 的序列 (a_i)a,(1leq ileq N),和 (q) 组询问,每组询问读入 (l_1,r_1,l_2,r_2),需输出(sumlimits_{x=0}^infty ext{get}(l_1,r_1,x) imes ext{get}(l_2,r_2,x)) 表示计算区间 ([l,r]) 中,数字 (x) 出现了多少次。
Analysis
可以离线每次都给你询问一个区间我们很容易想到这是一道莫队题。但这题的询问是两个区间,我们想办法把其拆成一个区间。
通过容斥,可以得到答案即为 ((get(1,r_1,x)-get(1,l_1)) imes (get(1,r_2,x)-get(1,l_2,x))),拆开后我们发现我们只要解决 (get(1,l,x) imes get(1,r,x)) 的问题。而我们发现这里其实只有两个变量 (l,r)。可是这跟普通的莫队又不太一样,其实只需改一下扩展即可,也就是l减小即删除,增大即增加,r也一样,然后就做完了。
所以如果这种多个区间的问题以后我们不妨考虑一下化成一个区间。
记住莫队其实只是排序的过程,而扩展不是不变的,根据不同的问题会有不同的扩展形式,也可能有不同的扩展方法。
代码的话也非常简短:
#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
template <typename T> void read(T &x) {
T f = 1;
char ch = getchar();
for (; '0' > ch || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (x = 0; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
x *= f;
}
int n, m;
int a[N];
int cnt[2][N];
int len, bl[N];
struct node{
int l, r, f, id;
friend bool operator < (node x, node y) {
if (bl[x.l] != bl[y.l]) return x.l < y.l;
if (bl[x.l] % 2) return x.r < y.r;
return x.r > y.r;
}
}q[N << 2];
int ans[N];
int top;
int nowl = 0, nowr = 0, nowans = 0;
void add(int id, int c) {
nowans -= cnt[0][c] * cnt[1][c];
cnt[id][c]++;
nowans += cnt[0][c] * cnt[1][c];
}
void del(int id, int c) {
nowans -= cnt[0][c] * cnt[1][c];
cnt[id][c]--;
nowans += cnt[0][c] * cnt[1][c];
}
void Push(int l, int r, int f, int id) {
if (l > r) swap(l, r);
q[++top] = node{l, r, f, id};
}
int main() {
read(n);
for (int i = 1; i <= n; i++) read(a[i]);
len = sqrt(n);
for (int i = 1; i <= n; i++) bl[i] = (i - 1) / len + 1;
read(m);
for (int i = 1, l1, r1, l2, r2; i <= m; i++) {
read(l1); read(r1); read(l2); read(r2);
l1--, l2--;
if (l1 == 0 && l2 == 0) {
Push(r1, r2, 1, i);
} else if (l1 == 0) {
Push(r1, r2, 1, i);
Push(r1, l2, -1, i);
} else if (l2 == 0) {
Push(r1, r2, 1, i);
Push(l1, r2, -1, i);
} else {
Push(r1, r2, 1, i);
Push(r1, l2, -1, i);
Push(l1, r2, -1, i);
Push(l1, l2, 1, i);
}
}
sort(q + 1, q + 1 + top);
for (int i = 1; i <= top; i++) {
while (nowl < q[i].l) add(0, a[++nowl]);
while (nowr < q[i].r) add(1, a[++nowr]);
while (nowl > q[i].l) del(0, a[nowl--]);
while (nowr > q[i].r) del(1, a[nowr--]);
ans[q[i].id] += nowans * q[i].f;
}
for (int i = 1; i <= m; i++) {
printf("%d
", ans[i]);
}
return 0;
}