题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式:
第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
输出格式:
M 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
输入样例#1:
6 1 2 3 4 3 5 3 1 2 3 5 2 6
输出样例#1:
2 2 4
说明
数据范围:
对于100%的数据,N <= 500000,M <= 500000。
解题思路
用树状数组求区间[x,y]的和时,是用query(y)-query(x-1),前y个值的和减去前x-1个。按照这个思路,在以y为r的区间里,关键的是一个元素出现的最右边的位置,因为左边会被减掉。所以如果存在重复出现的数,只要保留右边这个就可以了,把左边的去掉。
比如说用tree[]来维护b[](b[i]为1时表示a[i]这个元素值在当前区间内出现的最右位置为i,这句话有点绕,看下去就知道了),先把两个数组都初试化为0,如果要处理的贝壳序列是 1 3 3 2 2,先处理第一个数1,因为前面不存在1,那么就把b[1]+=1。第二个数3,因为前面不存在3,那么就把b[2]+=1。第三个数3,因为在位置2已经有一个3(开个last[]数组存上一个i出现的位置),但是在区间[1,3]里,位置3的3才是最右边的3,所以把b[2]-=1,b[3]+=1。因为左边重复的都已经变成0了,所以直接query(y) - query(x-1)就没问题了。
还有就是因为需要查询的指令很多,所以要存一下,然后按照r的值排序,因为输出答案的时候还是要按照对应输入的次序输出,所以也要存一下,不然排完序就乱了。排完序遍历指令扫过去一遍,开个存答案的数组把对应次序的答案按下标存进去,最后输出就好了。
代码如下
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
int tree[500005]; //树状数组
int a[500005]; //原数组
int last[1000005]; //i上一次出现的位置
int ans[500005]; //答案数组
struct T{
int l, r, i;
T() = default;
T(int l, int r, int i): l(l), r(r), i(i){ }
}ins[500005]; //记录询问区间以及此区间排在第几个
bool cmp(T a, T b)
{
return a.r < b.r;
}
int n;
int lowbit(int x)
{
return x & (-x);
}
void update(int x, int k) //更新
{
for(int i = x; i <= n; i += lowbit(i))
tree[i] += k;
}
int query(int x)
{
int sum = 0;
for(int i = x; i > 0; i -= lowbit(i))
sum += tree[i];
return sum;
}
int main()
{
while(cin >> n){
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
memset(tree, 0, sizeof(tree));;
memset(last, 0, sizeof(last));
int m;
cin >> m;
for(int i = 0; i < m; i ++){
int x, y;
scanf("%d%d", &x, &y);
ins[i] = T(x, y, i);
}
sort(ins, ins + m, cmp);
int s = 1;
for(int i = 0; i < m; i ++){
for(; s <= ins[i].r; s ++){
int num = a[s];
if(last[num]){
update(last[num], -1);
}
update(s, 1);
last[num] = s;
}
ans[ins[i].i] = query(ins[i].r) - query(ins[i].l - 1);
}
for(int i = 0; i < m; i ++)
printf("%d\n", ans[i]);
}
return 0;
}