-
首先非常显然的 答案=颜色总数-数量为1的颜色数
-
如果只有一次询问:
-
考虑如何算颜色总数:
如果将每一个颜色在当前询问的最右边的位置赋为1,其余位置赋为0的话,是不是就是一个区间和呢?
用查询数组1表示。 -
考虑如何算数量为1的颜色数:
如果将每一个颜色在当前区间的位置赋为1,该颜色的前一个位置赋为-1,其余位置赋为0,是不是这又变成了一个区间和呢?
用查询数组2表示。 -
为什么这是对的呢:
如果该区间包含了多个x的话其实只用考虑最后两个即可,倒数第三个第四个无关紧要,完全可以缩为0。
-
-
接下来考虑多次询问:
- 如何如果右端点r固定每次将左端点l右移:
问题就非常简单了吧,只要将右端点所包括的点做成单次询问的查询数组即可,左端点的右移仅仅会影响询问而不会影响查询数组的值。 - 如果右端点会不断右移呢:
我们只要使得查询数组仍然成立即可。
如果每次添加一个点x则将查询数组1中x的上一个位置赋为0,当前位置赋为1;将查询数组2中x的上上个位置赋为0,上个位置赋为-1,当前位置赋为1即可 - 如何保证上述条件呢:
将问题离线,以右端点r为关键字排序即可。
- 如何如果右端点r固定每次将左端点l右移:
-
注意点:由于n的范围所以要用树状数组来维护区间和。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline long long _read() {
long long ans; char c;
for (c = getchar(); c<'0' || c>'9'; c = getchar());
for (ans = 0; c <= '9'&&c >= '0'; c = getchar()) ans = ans * 10 + c - '0';
return ans;
}
long long write_node[20], write_i;
inline void _write(long long ans) {
if (!ans) putchar('0');
for (write_i = 1; ans; write_i++, ans /= 10) write_node[write_i] = ans % 10;
for (write_i--; write_i; write_i--) putchar(write_node[write_i] + '0');
putchar('\n'); return;
}
struct TT {
#define lowbit(x) x&(-x)
int a[2000001], n;
inline void inin(int x) {
n = x;
memset(a, 0, sizeof a);
return;
}
inline int ask(int pos) {
register int ans = 0;
for (register int i = pos; i; i -= lowbit(i)) ans += a[i];
return ans;
}
inline void change(int pos, int tag) {
if (pos == 0) return;
for (register int i = pos; i <= n; i += lowbit(i)) a[i] += tag;
return;
}
}f1, f2; //查询数组
struct TTT {
int l, r, pos;
}t[2000001];
int n, q;
int pre[2000001], last[2000001], a[2000001], ans[2000001];
inline bool cmd(TTT t1, TTT t2) {
return t1.r < t2.r;
}
inline void inin() {
n = _read(); q = _read(); q = _read();
for (register int i = 1; i <= n; ++i) a[i] = _read();
memset(last, 0, sizeof last);
for (register int i = 1; i <= n; ++i) pre[i] = last[a[i]], last[a[i]] = i;
for (register int i = 0; i < q; ++i) t[i].l = _read(), t[i].r = _read(), t[i].pos = i;
sort(t, t + q, cmd);
return;
}
int main() {
inin();
f1.inin(n); f2.inin(n);
for (register int i = 0, r = 1; i < q; ++i) {
while (r <= t[i].r&&r <= n) {
f1.change(pre[r], -1);
f1.change(r, 1);
f2.change(pre[pre[r]], 1);
f2.change(pre[r], -2);
f2.change(r, 1);
++r;
}
ans[t[i].pos] = f1.ask(t[i].r) - f1.ask(t[i].l - 1) - f2.ask(t[i].r) + f2.ask(t[i].l - 1);
}
for (register int i = 0; i < q; ++i) _write(ans[i]);
return 0;
}