题意
题解
std::bitset 维护区间元素,由于需要统计相同值的元素出现的个数,离散化时不做去重处理,那么有序数组的相邻元素 a i , a i + 1 a_i,a_{i+1} ai,ai+1 的最小索引之间的距离(同时也是离散化的值之间的距离)为 a i a_i ai 在数组中出现的个数,那么对于 c n t [ a i ] cnt[a_i] cnt[ai] 个 a i a_i ai,只需要将 std::bitset 的 [ a i , a i + c n t [ a i ] ) [a_i,a_i+cnt[a_i]) [ai,ai+cnt[ai]) 位设为 1 1 1 即可,此时三个区间对应的 std::bitset 的交集即为所求。
用莫队算法维护求解区间 std::bitset 即可。总时间复杂度 O ( n n + n 2 / 32 ) O(n\sqrt{n}+n^2/32) O(nn+n2/32)。
考虑到空间开销过大,实现上将询问分为常数段进行处理。
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int MAXN = 1E5 + 5, B = 3;
typedef bitset<MAXN> bt;
int N, M, A[MAXN];
int L[MAXN], R[MAXN], idx[MAXN], res[MAXN];
int cnt[MAXN], sx[MAXN], sxn, lim;
struct Query
{
int l, r, id;
bool operator<(const Query &o)
{
if (idx[l] != idx[o.l])
return idx[l] < idx[o.l];
return (idx[l] & 1) ? r < o.r : r > o.r;
}
} qs[MAXN];
bt rec[MAXN / B], tmp;
void add(int i) { tmp[A[i] + cnt[A[i]]++] = 1; }
void del(int i) { tmp[A[i] + --cnt[A[i]]] = 0; }
void solve()
{
int n = 0;
for (int i = 0; i < lim && M--; ++i, n += 3)
{
rec[i].set();
res[i] = 0;
for (int j = 0; j < 3; ++j)
{
auto &q = qs[n + j];
cin >> q.l >> q.r;
--q.l, q.id = i;
res[i] += q.r - q.l;
}
}
sort(qs, qs + n);
memset(cnt, 0, sizeof(cnt));
tmp.reset();
for (int i = 0, l = qs[0].l, r = l; i < n; ++i)
{
int ql = qs[i].l, qr = qs[i].r;
while (ql < l)
add(--l);
while (r < qr)
add(r++);
while (l < ql)
del(l++);
while (qr < r)
del(--r);
rec[qs[i].id] &= tmp;
}
for (int i = 0; i < n / 3; ++i)
{
int num = rec[i].count();
cout << res[i] - 3 * num << '\n';
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> M;
for (int i = 0; i < N; ++i)
cin >> A[i];
int sz = ceil(sqrt(N));
for (int l = 0, i = 0; l < N; l += sz, ++i)
{
L[i] = l, R[i] = min(l + sz, N);
for (int j = L[i]; j < R[i]; ++j)
idx[j] = i;
}
for (int i = 0; i < N; ++i)
sx[sxn++] = A[i];
sort(sx, sx + sxn);
for (int i = 0; i < N; ++i)
A[i] = lower_bound(sx, sx + sxn, A[i]) - sx;
lim = M / B + 1;
for (int i = 0; i < B; ++i)
solve();
return 0;
}