AT_abc242_g
做法
一道挺板子的莫队。
所谓莫队算法,其实就是暴力算法的优化。暴力算法是按询问的左右端点排序,然后暴力得到答案的,而莫队是把询问左右端点所属的块进行排序,再与暴力一样得到答案。优化后,时间复杂度变成了 \(\mathcal{O(n \sqrt n)}\)。
再回到这道题。我们将询问离线,分块,接着按左右端点属于的块进行排序,最后暴力得到答案。
code:
#include <bits/stdc++.h>
#define int long long
const int N = 5e5 + 5, M = 1e6 + 5, MOD = 1000007;
using namespace std;
inline int read(){
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
int n, m, len, res;
int f[N], cnt[N], ans[M];
struct query
{
int l, r, id;
}q[M];
bool cmp (query x, query y)
{
return (x.r / len) == (y.r / len) ? x.l < y.l : x.r < y.r;
}
void del(int k)
{
res -= (cnt[f[k]] / 2);
cnt[f[k]] --;
res += (cnt[f[k]] / 2);
}
void add(int k)
{
res -= (cnt[f[k]] / 2);
cnt[f[k]] ++;
res += (cnt[f[k]] / 2);
}
signed main()
{
n = read();
for (int i = 1; i <= n; i ++ ) f[i] = read();
m = read();
for (int i = 1, x, y; i <= m; i ++ )
{
x = read(), y = read();
q[i] = {x, y, i};
}
len = n / (sqrt((m * 2 / 3)));
sort(q + 1, q + m + 1, cmp);
int l = 0, r = 0;
for (int i = 1; i <= m; i ++ )
{
int ql = q[i].l, qr = q[i].r;
while (l < ql) del(l ++);
while (r > qr) del(r --);
while (l > ql) add(-- l);
while (r < qr) add(++ r);
ans[q[i].id] = res;
}
for (int i = 1; i <= m; i ++ ) cout << ans[i] << '\n';
}