[Ybt Gold Medal Navigation 6-4-1] Different numbers in intervals / Mo team example

Different number of intervals

Topic link: ybt gold medal navigation 6-4-1

General idea

There is a sequence, which is asked multiple times, and how many kinds of numbers are in an interval each time.

Ideas

There are many ways to do this, tree array, chair tree can be used.

But because the data for this question is relatively small and supports offline, we use a simpler and better algorithm-Team Mo.

What is Team Mo?
It is to slide the left and right sides of your interval, and then slide to the inquiry in a certain order.
Then the boundary sliding a distance is O (1) O (1)O ( 1 ) , then we are like how to make it slide less frequently.

How do you do it?
One way is to divide into blocks. The first keyword for query sorting is the number of the block on the left, and the second keyword is the number on the right.
Then the left one moves at most mnm\sqrt{n}mn Times (every time jump horizontally at the left and right of the block, and then ask how many times to jump), the right one moves at most nnn\sqrt{n}nn Times (every time the first and last horizontal jump, then horizontal jump n \sqrt{n}n The second left is at the end).

The total complexity is O ((n + m) n) O((n+m)\sqrt(n))O ( ( n+m)n )

Code

#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

struct node {
    
    
	int l, r, num;
}ask[500001];
int n, a[50001], K, answer, l, r;
int m, num[1000001], ans[200001];

int get_K(int x) {
    
    
	return (x - 1) / K;
}

bool cmp(node x, node y) {
    
    
	if (get_K(x.l) != get_K(y.l)) return get_K(x.l) < get_K(y.l);
	return x.r < y.r;
}

int main() {
    
    
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	K = floor(sqrt(n));//分块
	
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {
    
    
		scanf("%d %d", &ask[i].l, &ask[i].r);
		ask[i].num = i;
	}
	
	sort(ask + 1, ask + m + 1, cmp);
	//第一关键字:左边所属块的编号
	//第二关键字:右边的编号
	
	l = ask[1].l;//处理出一开始的
	r = ask[1].r;
	for (int i = l; i <= r; i++) {
    
    
		num[a[i]]++;
		if (num[a[i]] == 1) answer++;
	}
	ans[ask[1].num] = answer;
	
	for (int i = 2; i <= m; i++) {
    
    
		while (l < ask[i].l) {
    
    //滑动左边的
			num[a[l]]--;
			if (!num[a[l]]) answer--;
			l++;
		}
		while (l > ask[i].l) {
    
    
			l--;
			num[a[l]]++;
			if (num[a[l]] == 1) answer++;
		}
		
		while (r > ask[i].r) {
    
    //滑动右边的
			num[a[r]]--;
			if (!num[a[r]]) answer--;
			r--;
		}
		while (r < ask[i].r) {
    
    
			r++;
			num[a[r]]++;
			if (num[a[r]] == 1) answer++;
		}
		
		ans[ask[i].num] = answer;
	}
	
	for (int i = 1; i <= m; i++)
		printf("%d\n", ans[i]);
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/114026614