P1972 [SDOI2009] HH's Necklace (Mo Team Algorithm)

topic description

HH has a necklace made of various beautiful shells. HH believes that different shells bring good luck, so after each walk, he picks out a random piece of shell and ponders what they mean. HH keeps collecting new shells, so his necklace gets longer and longer.

One day, he suddenly raised a question: How many different kinds of shells are contained in a certain section of shells? This question is difficult to answer... because the necklace is too long. So, he had to turn to you, the wise, to solve this problem.

input format

One positive integer n per line, indicating the length of the necklace.
The second line contains n positive integers ai​, indicating the type of the i-th shell in the necklace.

The third line contains an integer m, indicating the number of H queries.
In the next m lines, each line contains two integers l, r, indicating the interval of the query.

output format

Output m lines, each line has an integer, which in turn indicates the corresponding answer to the query.

Input and output samples

Type #1 to copy

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

output #1 copy

2
2
4

Ideas:

Team Mo's Algorithm = Offline + Violence + Blocking

The basic Mo team algorithm is an offline algorithm. He is usually used for a class of interval problems that do not modify and only query, and the complexity is O(nsqrt(n)).

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
struct node {
	int L, R, k; // k为查询操作的原始顺序
}q[N];
int pos[N];
int ans[N];
int cnt[N];
int a[N];
bool cmp(node a, node b) { // 莫队算法 
	if (pos[a.L] != pos[b.L]) { // 左端点排序 
		return pos[a.L] < pos[b.L]; // 块的大小排序
	}
	if (pos[a.L] & 1) return a.R > b.R; //奇偶性优化
	return a.R < b.R;
	
	if (a.L == b.L) return a.R < b.R;
	return a.L < b.L;
}
int ANS = 0;
void add(int x) {
	cnt[a[x]] ++;
	if (cnt[a[x]] == 1) ANS++;
}
void del(int x) {
	cnt[a[x]] --;
	if (cnt[a[x]] == 0) ANS--;
}
int main() {
	int n;
	scanf("%d", &n);
	int block = sqrt(n); // 每一块的大小
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		pos[i] = (i - 1) / block + 1;//所属的块 从 1 ~ (n-1)/block + 1块
	}
	int m;
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &q[i].L, &q[i].R);
		q[i].k = i;
	}
	sort(q + 1, q + 1 + m, cmp);
	int L = 1, R = 0;
	for (int i = 1; i <= m; i++) {
		while (L < q[i].L) del(L++);
		while (R > q[i].R) del(R--);
		while (L > q[i].L) add(--L);
		while (R < q[i].R) add(++R);
		ans[q[i].k] = ANS;
	}
	for (int i = 1; i <= m; i++) {
		printf("%d\n", ans[i]);
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/zhi6fui/article/details/128573612