题目链接
【分析】
- 如果 N ≤ 5 × 1 0 4 N \leq 5 \times 10^4 N≤5×104,这就是莫队的模板题了。。。
- 但是 N ≤ 5 × 1 0 5 N \leq 5 \times 10^5 N≤5×105。。。
- 仍然考虑离线处理
- 将询问按左端点排序
- 预处理出每一种颜色第一次出现的位置,以及每个位置的下一个同色位置
- 用一个指针扫描每一个位置,表示当前的左端点
- 每扫描一个位置,就在该位置的下一个同色位置加 1 1 1
- 这样答案就是 S u m ( l , r ) Sum(l,r) Sum(l,r)
- 可以用树状数组维护
【代码】
#include<bits/stdc++.h>
#define b(x) ((x - 1) / sqn)
using namespace std;
const int maxn = 5e5 + 10;
const int maxm = 2e5 + 10;
int n, m, a[maxn << 2], sqn, tot, cnt[maxn << 2], ans[maxm << 2], sum = 0;
struct query
{
int rnk;
int l, r;
} q[maxm << 1];
struct cmp
{
inline bool operator () (const query &x, const query &y)
{
if(b(x.l) == b(y.l))
return x.r < y.r;
return x.l < y.l;
}
};
inline void add(int pos)
{
if(++cnt[a[pos]] == 1)
sum++;
}
inline void remove(int pos)
{
if(--cnt[a[pos]] == 0)
sum--;
}
inline int read()
{
static int x;
static char c;
x = 0, c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c))
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++)
a[i] = read();
m = read(), sqn = (n * n / m);
for(int i = 1; i <= m; i++)
{
q[i].l = read();
q[i].r = read();
q[i].rnk = i;
}
sort(q + 1, q + m + 1, cmp());
int mol = 0, mor = 0;
for(int i = 1; i <= m; i++)
{
int l = q[i].l, r = q[i].r, rnk = q[i].rnk;
while(mol < l)
remove(mol++);
while(mor > r)
remove(mor--);
while(mol > l)
add(--mol);
while(mor < r)
add(++mor);
ans[rnk] = sum;
}
for(int i = 1; i <= m; i++)
printf("%d\n", ans[i]);
return 0;
}