BZOJ_1878_[SDOI2009]HH的项链_莫队

BZOJ_1878_[SDOI2009]HH的项链_莫队

Description

HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。

Input

第一行:一个整数N,表示项链的长度。 
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。 
第三行:一个整数M,表示HH询问的个数。 
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。

Output

M行,每行一个整数,依次表示询问对应的答案。

Sample Input

6
1 2 3 4 3 5
3
1 2
3 5
2 6

Sample Output

2
2
4


 

分析:离线莫队。

维护每个数出现的次数和答案即可。

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define N 500050
int h[1000050], pos[N], block, now, c[N], n, q;
struct A {
	int s, t, id, ans;
}a[N];
bool cmp1(const A &x,const A &y) {
	if(pos[x.s] == pos[y.s]) return x.t < y.t;
	return pos[x.s] < pos[y.s];
}
bool cmp2(const A &x,const A &y) {return x.id < y.id; }
void pushup(int x, int sig) {
	if(sig == 1) {
		h[c[x]] ++;
		if(h[c[x]] == 1) now ++;
	}else {
		h[c[x]] --;
		if(h[c[x]] == 0) now --;
	}
}
int main() {
	scanf("%d", &n);
	int i, j, l, r = 0;
	for(i = 1;i <= n; ++ i) scanf("%d", &c[i]);
	block = sqrt(n);
	for(i = 1;i <= block; ++ i) {
		l = r + 1;
		r = i * block;
		for(j = l;j <= r; ++ j) pos[j] = i;
	}
	if(r != n) {
		l = r + 1;
		r = n;
		block ++;
		for(i = l;i <= r; ++ i) pos[i] = block;
	}
	scanf("%d",&q);
	for(i = 1;i <= q; ++ i) scanf("%d%d",&a[i].s,&a[i].t), a[i].id = i;
	sort(a + 1, a + q + 1, cmp1);
	for(l = 1, r = 0, i = 1;i <= q; ++ i) {
		while(l < a[i].s) pushup(l, -1), ++ l;
		while(l > a[i].s) pushup(l - 1, 1), -- l;
		while(r > a[i].t) pushup(r, -1), -- r;
		while(r < a[i].t) pushup(r + 1, 1), ++ r;
		a[i].ans = now;
	}
	sort(a + 1, a + q + 1, cmp2);
	for(i = 1;i <= q; ++ i) printf("%d\n", a[i].ans);
}

 

posted @ 2018-03-30 19:01  fcwww  阅读(103)  评论(0编辑  收藏  举报