[Ybt gold medal navigation 6-3-1] [luogu P4168] interval mode/dandelion/block example

Interval Mode / Dandelion

Topic link: ybt gold medal navigation 6-3-1 / luogu P4168

General idea

Given a sequence, find the mode of an interval at a time.
Mode: The number with the most occurrences. If there are multiple numbers, choose the smaller one.
Mandatory online.

Ideas

This question is an example question in blocks.

Blocking is to divide the sequence of numbers into many blocks, and then these blocks can be counted as a whole.
In this case, if you want to inquire about the interval every time, you can divide it into three parts: the extra front, the extra extra, and the middle interval.
We can directly violent the extra front and back, and then we can get a prefix and or something in the middle to quickly figure it out.

Then we think about the blocks, what is the optimal size of each block.
You have to worry about the number of blocks and the size of the blocks. Then we will make these two as the same as possible, that is n \sqrt{n}n The size, divided into approximately n \sqrt{n}n segment.
(It's probably because there will be a little more in the end, but it doesn't matter, just forget it)

Then this question is like this, but you see that the numbers are very large, and then you decide to record the number of times each number appears in the interval.
Then discretize the numbers and follow the above method.

Then you can look at the code for details.

Code

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

using namespace std;

struct node {
    
    
	int x, num, val;
}a[40001];
int n, m, dy[40001], tot, K;
int num[201][40001], x, y, ans;
int sum[40001], maxn, maxx;

bool cmp(node x, node y) {
    
    
	return x.x < y.x;
}

bool cmp_b(node x, node y) {
    
    
	return x.num < y.num;
}

int work(int x, int y) {
    
    
	maxn = -1;
	memset(sum, 0, sizeof(sum));
	
	while (x % K != 0 && x <= y) {
    
    //处理前面的多出来的
		sum[a[x].val]++;
		if (sum[a[x].val] > maxn) {
    
    
			maxn = sum[a[x].val];
			maxx = a[x].val;
		}
		else if (sum[a[x].val] == maxn && a[x].val < maxx) {
    
    
			maxx = a[x].val;
		}
		x++;
	}
	while (y % K != K - 1 && x <= y) {
    
    //处理后面多出来的
		sum[a[y].val]++;
		if (sum[a[y].val] > maxn) {
    
    
			maxn = sum[a[y].val];
			maxx = a[y].val;
		}
		else if (sum[a[y].val] == maxn && a[y].val < maxx) {
    
    
			maxx = a[y].val;
		}
		y--;
	}
	
	if (x > y) {
    
    //没有中间的大块
		return dy[maxx];
	}
	
	for (register int i = 0; i <= tot; i++) {
    
    //枚举数
		sum[i] += num[y / K][i] - ((x / K - 1 < 0) ? 0 : num[x / K - 1][i]);
		//利用前缀和算出大区间中有多少个这个数
		if (sum[i] > maxn) {
    
    
			maxn = sum[i];
			maxx = i;
		}
		else if (sum[i] == maxn && i < maxx) {
    
    
			maxx = i;
		}
	}
	
	return dy[maxx];
}

int read() {
    
    
	int re = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
    
    
		re = re * 10 + c - '0';
		c = getchar();
	}
	return re;
}

void write(int now) {
    
    
	if (now > 9) write(now / 10);
	putchar(now % 10 + '0');
}

int main() {
    
    
	n = read();
	m = read();
	for (register int i = 0; i < n; i++) {
    
    
		a[i].x = read();
		a[i].num = i;
	}
	
	sort(a, a + n, cmp);//离散化
	a[0].val = 0;
	dy[tot] = a[0].x;
	for (register int i = 1; i < n; i++) {
    
    
		if (a[i].x != a[i - 1].x) {
    
    
			tot++;
			dy[tot] = a[i].x;
		}
		a[i].val = tot;
	}
	sort(a, a + n, cmp_b);
	
	K = floor(sqrt(n));//分块
	for (register int i = 0; i < n; i++) {
    
    //算每个块每个数字的数量
		num[i / K][a[i].val]++;
	}
	for (register int i = 1; i < n / K; i++)//前缀和算1~i个块中数字j的数量有多少个
		for (register int j = 0; j <= tot; j++)
			num[i][j] += num[i - 1][j];
	
	for (register int i = 1; i <= m; i++) {
    
    
		x = read();
		y = read();
		x = ((x + ans - 1) % n) + 1;
		y = ((y + ans - 1) % n) + 1;
		if (x > y) swap(x, y);//解码
		
		x--;//因为我是从0编号,所以编号要减一
		y--;
		
		ans = work(x, y);
		
		write(ans);
		putchar('\n');
	}
	
	return 0;
}

Guess you like

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