P1972
[SDOI2009]HH的项链
题目大意:对于给定的每一个区间([l,r]),查询其中不同的数的个数
做法:按照每个区间的(r)从小到大排序,最近做的题思想都比较巧妙(
将区间按照(r)的值从小到大排序之后,从前往后扫,考虑扫到一个区间的(r)的时候统计答案,如果这个数之前出现过,如果后面还出现了,那么前面的数就没有存在的意义了,因为(r)是从小到大排序的,
从前往后扫逐一回答每个区间的答案。从前往后扫的时候如果这个数之前没有出现过那么就把树状数组的这个位置变成(1),如果之前出现了这个数字那么就把这个数字原来的位置变为(0),(r)是从小到大排序的,那么越靠前对答案产生贡献的可能性就越小,然后将现在的位置变为(1),同时更新这个数出现的位置。用树状数组查询。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e6+7;
int n,m,a[maxn],tree[maxn],ans[maxn];
int last_pos = 1,pos[maxn];
struct qwq{
int L,R,id;
bool operator < (const qwq &C)const
{
return R < C.R;
}
}e[maxn];
inline int read()
{
int x = 0,f = 1;
char c;
while(!isdigit(c = getchar()))
if(c == '-') f = -1;
while(isdigit(c))
x = (x << 3) + (x << 1) + (c & 15),c = getchar();
return x * f;
}
int lowbit(int k)
{
return k & -k;
}
void add(int x,int k)
{
for(;x<=n;x+=lowbit(x))
tree[x] += k;
return ;
}
int sum(int x)
{
int res = 0;
for(;x;x-=lowbit(x))
res += tree[x];
return res;
}
int main()
{
n = read();
for(int i=1;i<=n;i++)
a[i] = read();
m = read();
for(int i=1;i<=m;i++)
{
e[i].L = read();e[i].R = read();
e[i].id = i;
}
sort(e+1,e+m+1);
for(int i=1;i<=m;i++)
{
for(int j=e[i-1].R+1;j<=e[i].R;j++)
{
if(pos[a[j]])
add(pos[a[j]],-1);
pos[a[j]] = j;
add(j,1);
}
ans[e[i].id] = sum(e[i].R) - sum(e[i].L-1);
}
for(int i=1;i<=m;i++)
printf("%d
",ans[i]);
return 0;
}