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;
}
posted @ 2023-04-18 19:51  N0zoM1z0  阅读(9)  评论(0编辑  收藏  举报