P1972
[SDOI2009] HH的项链
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。
有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入格式
一行一个正整数 \(n\),表示项链长度。
第二行 \(n\) 个正整数 \(a_i\),表示项链中第 \(i\) 个贝壳的种类。
第三行一个整数 \(m\),表示 HH 询问的个数。
接下来 \(m\) 行,每行两个整数 \(l,r\),表示询问的区间。
输出格式
输出 \(m\) 行,每行一个整数,依次表示询问对应的答案。
样例 #1
样例输入 #1
6
1 2 3 4 3 5
3
1 2
3 5
2 6
样例输出 #1
2
2
4
提示
【数据范围】
对于 \(20\%\) 的数据,\(1\le n,m\leq 5000\);
对于 \(40\%\) 的数据,\(1\le n,m\leq 10^5\);
对于 \(60\%\) 的数据,\(1\le n,m\leq 5\times 10^5\);
对于 \(100\%\) 的数据,\(1\le n,m,a_i \leq 10^6\),\(1\le l \le r \le n\)。
树状数组 + 离散化询问
考虑求的是种类数 所以晚出现的数占决定性作用 按询问区间右端点升序排列
用一个jl[]记录每种颜色对应的最靠右的位置 找到新的就将原位置删除 add(jl[a[j]],-1) add(a[j],1) jl[a[j]]=j
每次枚举区间从 上一个的 r[i-1]+1 到 r[i]
这样总共遍历了 n个元素 每次操作为 logn 总 O(nlogn)极为优秀
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int N=1e6+5;
int n,a[N],tr[N],m;
char *p1,*p2,buf[100000];
char nc() {
static char buf[1<<14],*be=buf,*ed=buf;
if(be==ed) be=buf,ed=buf+fread(buf,1,1<<14,stdin);
return be==ed ? EOF:*be++;
}
inline void read(int& x) {
x=0;
int f=1;
char ch=nc();
while(ch<48||ch>57) {
if(ch=='-')f=-1;
ch=nc();
}
while(ch>=48&&ch<=57)
x=10*x+ch-'0',ch=nc();
x=x*f;
}
int lowbit(int x) {
return x&(-x);
}
inline void add(int p,int x) {
for(; p<=n; p+=lowbit(p))
tr[p]+=x;
}
inline int ask(int p) {
int sum=0;
for(; p; p-=lowbit(p))
sum+=tr[p];
return sum;
}
struct Query {
int l,r,id;
} q[N];
inline bool cmp(Query x,Query y) {
return x.r<y.r;
}
void write(int x) {
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
return ;
}
int jl[N],ans[N];
signed main() {
read(n);
for(register int i=1; i<=n; ++i)read(a[i]);
read(m);
int l,r;
for(register int i=1; i<=m; ++i)
read(l),read(r),q[i].l=l,q[i].r=r,q[i].id=i;
sort(q+1,q+m+1,cmp);
int L=1;
for(register int i=1; i<=m; i++) {
for(register int j=L; j<=q[i].r; ++j) {
if(jl[a[j]])add(jl[a[j]],-1);
add(j,1);
jl[a[j]]=j;
}
ans[q[i].id]=ask(q[i].r)-ask(q[i].l-1);
L=q[i].r+1;
}
for(register int i=1; i<=m; ++i)
write(ans[i]),putchar('\n');
return 0;
}