题意:给出一个数列,每个询问查询[L,R]中至少出现两次的数字有多少种?
思路:(1)记录每个位置i的数字的前一个相同数字出现的位置pre[i],没有前一个相同的pre[i]为0。
(2)询问按照R升序。
(3)开始计算:枚举i从1到m(m为询问个数),对于某个位置x,将pre[pre[x]]+1增加1,pre[x]+1减少1,这样做的原因在于任意一个出现两次的数字在任意一段区间中最多只插入一次。然后统计左区间之前的和即可。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1000010;
struct Node
{
int l, r, id;
Node() {}
Node(int t_l, int t_r, int t_id) : l(t_l), r(t_r), id(t_id) {}
bool operator < (const Node &p) const
{
if(r == p.r)
return l < p.l;
return r < p.r;
}
}node[MAXN];
int Tree[MAXN], pre[MAXN], head[MAXN], ans[MAXN], a[MAXN], n, c, m;
inline int lowbit(int x)
{
return x & (-x);
}
void modify(int x, int value)
{
for(int i = x; i <= n; i += lowbit(i))
{
Tree[i] += value;
}
return ;
}
int getsum(int x)
{
int ret = 0;
for(int i = x; i > 0; i -= lowbit(i))
{
ret += Tree[i];
}
return ret;
}
int main()
{
//freopen("aa.in", "r", stdin);
//freopen("bb.out", "w", stdout);
scanf("%d %d %d", &n, &c, &m);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
pre[i] = head[a[i]];
head[a[i]] = i;
}
for(int i = 1; i <= m; ++i)
{
scanf("%d %d", &node[i].l, &node[i].r);
node[i].id = i;
}
sort(node + 1, node + m + 1);
int now = 1;
for(int i = 1; i <= m; ++i)
{
while(now <= node[i].r)
{
modify(pre[pre[now]] + 1, 1);
modify(pre[now] + 1, -1);
now++;
}
ans[node[i].id] = getsum(node[i].l);
}
for(int i = 1; i <= m; ++i)
{
printf("%d\n", ans[i]);
}
return 0;
}