描述
给定一个长度为 n n n 的序列 a a a, q q q 次询问。每次询问给定 l 1 , r 1 , l 2 , r 2 l_1,r_1,l_2,r_2 l1,r1,l2,r2,求 ∑ x = 0 ∞ get ( l 1 , r 1 , x ) ⋅ get ( l 2 , r 2 , x ) \sum\limits_{x=0}^\infty \text{get}(l_1,r_1,x)\cdot\text{get}(l_2,r_2,x) x=0∑∞get(l1,r1,x)⋅get(l2,r2,x)。
get ( l , r , x ) \text{get}(l,r,x) get(l,r,x) 表示计算区间 [ l , r ] [l,r] [l,r] 中,数字 x x x 出现了多少次。
思路
考虑容斥,即 get ( l , r , x ) = get ( 1 , r , x ) − get ( 1 , l − 1 , x ) \text{get}(l,r,x)=\text{get}(1,r,x)-\text{get}(1,l-1,x) get(l,r,x)=get(1,r,x)−get(1,l−1,x)。
再来化简式子:
∑ x = 0 ∞ get ( l 1 , r 1 , x ) ⋅ get ( l 2 , r 2 , x ) = ∑ x = 0 ∞ [ get ( 1 , r 1 , x ) − get ( 1 , l 1 − 1 , x ) ] ⋅ [ get ( 1 , r 2 , x ) − get ( 1 , l 2 − 1 , x ) ] \sum\limits_{x=0}^\infty \text{get}(l_1,r_1,x)\cdot\text{get}(l_2,r_2,x) =\sum\limits_{x=0}^\infty [\text{get}(1,r_1,x)-\text{get}(1,l_1-1,x)]\cdot[\text{get}(1,r_2,x)-\text{get}(1,l_2-1,x)] x=0∑∞get(l1,r1,x)⋅get(l2,r2,x)=x=0∑∞[get(1,r1,x)−get(1,l1−1,x)]⋅[get(1,r2,x)−get(1,l2−1,x)]
记 g ( p ) = get ( 1 , p , x ) \text{g}(p)=\text{get}(1,p,x) g(p)=get(1,p,x),即 1 ∼ p 1\sim p 1∼p 中 x x x 的出现次数。
展开,得:
∑ x = 0 ∞ g ( r 1 ) ⋅ g ( r 2 ) − ∑ x = 0 ∞ g ( r 1 ) ⋅ g ( l 2 − 1 ) − ∑ x = 0 ∞ g ( l 1 − 1 ) ⋅ g ( r 2 ) + ∑ x = 0 ∞ g ( l 1 − 1 ) ⋅ g ( l 2 − 1 ) \sum\limits_{x=0}^\infty \text{g}(r_1)\cdot\text{g}(r_2)-\sum\limits_{x=0}^\infty\text{g}(r_1)\cdot\text{g}(l_2-1)- \sum\limits_{x=0}^\infty\text{g}(l_1-1)\cdot\text{g}(r_2)+ \sum\limits_{x=0}^\infty\text{g}(l_1-1)\cdot\text{g}(l_2-1) x=0∑∞g(r1)⋅g(r2)−x=0∑∞g(r1)⋅g(l2−1)−x=0∑∞g(l1−1)⋅g(r2)+x=0∑∞g(l1−1)⋅g(l2−1)
这样就把一次询问强行拆成了 4 4 4 次询问, 4 4 4 次询问的和(差)即为答案。
记二元组 ( l , r ) (l,r) (l,r) 表示一小次询问 ± ∑ x = 0 ∞ g ( l ) ⋅ g ( r ) \pm\sum\limits_{x=0}^\infty\text{g}(l)\cdot\text{g}(r) ±x=0∑∞g(l)⋅g(r),即所有数在 1 ∼ l 1\sim l 1∼l 的出现次数 × \times × 在 1 ∼ r 1\sim r 1∼r 的出现次数。
发现从 ( l , r ) (l,r) (l,r) 转移到 ( l ′ , r ′ ) (l',r') (l′,r′) 的暴力转移的时间复杂度是 O ( abs ( l ′ − l ) + abs ( r ′ − r ) ) \mathcal{O}(\text{abs}(l'-l)+\text{abs}(r'-r)) O(abs(l′−l)+abs(r′−r)),可以直接莫队。
代码
#include <bits/stdc++.h>
using namespace std;
#define re register
#define int unsigned
#define MAXN 100010
int n, k, m, a[MAXN], len, sum, bel[MAXN], geta[MAXN], getl[MAXN], getr[MAXN], ans[MAXN];
struct ques {
int i, l, r, z;
ques() {}
ques(const int &a, const int &b, const int &c, const int &d) {
i = a, l = b, r = c, z = d;
}
} q[MAXN << 2];
inline bool cmp(const ques &a, const ques &b) {
if (bel[a.l] != bel[b.l]) return a.l < b.l;
if (bel[a.l] & 1) return a.r < b.r;
else return a.r > b.r;
}
inline void update_r(const int &c) {
sum -= geta[c]; geta[c] += getl[c]; getr[c]++; sum += geta[c];
}
inline void update_l(const int &c) {
sum -= geta[c]; geta[c] += getr[c]; getl[c]++; sum += geta[c];
}
inline void remove_r(const int &c) {
sum -= geta[c]; geta[c] -= getl[c]; getr[c]--; sum += geta[c];
}
inline void remove_l(const int &c) {
sum -= geta[c]; geta[c] -= getr[c]; getl[c]--; sum += geta[c];
}
signed main() {
cin >> n;
for (register int i = 1; i <= n; i++) cin >> a[i];
cin >> k;
for (register int i = 1; i <= k; i++) {
int l1, r1, l2, r2;
cin >> l1 >> r1 >> l2 >> r2;
q[++m] = ques(i, r1, r2, 1), q[++m] = ques(i, r1, l2 - 1, -1), q[++m] = ques(i, l1 - 1, r2, -1), q[++m] = ques(i, l1 - 1, l2 - 1, 1);
}
len = n / sqrt(n * 2 / 3);
for (register int i = 1; i <= n; i++) bel[i] = (i - 1) / len + 1;
sort(q + 1, q + m + 1, cmp);
int l = 0, r = 0;
for (register int i = 1; i <= m; i++) {
for (register int j = l + 1; j <= q[i].l; j++) update_l(a[j]);
for (register int j = l; j > q[i].l; j--) remove_l(a[j]);
for (register int j = r + 1; j <= q[i].r; j++) update_r(a[j]);
for (register int j = r; j > q[i].r; j--) remove_r(a[j]);
l = q[i].l, r = q[i].r;
ans[q[i].i] += q[i].z * sum;
}
for (register int i = 1; i <= k; i++) cout << ans[i] << endl;
return 0;
}