区间分块-洛谷P4168

1 篇文章 0 订阅
1 篇文章 0 订阅

洛谷P4168

更多好文章

题目描述

把所有的蒲公英看成一个长度为 n n n 的序列 { a 1 , a 2 . . a n } \{a_1,a_2..a_n\} {a1,a2..an},其中 a i a_i ai 为一个正整数,表示第 i i i 棵蒲公英的种类编号。

而每次询问一个区间 [ ( ( l + x − 1 ) m o d    n ) + 1 , ( ( r + x − 1 ) m o d    n ) + 1 ] [((l+x-1)\mod n)+1, ((r+x-1)\mod n)+1] [((l+x1)modn)+1,((r+x1)modn)+1],其中 x x x 表示上一次询问的答案,需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。

数据规模

  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 40000 1\le n \le 40000 1n40000 1 ≤ m ≤ 50000 1\le m \le 50000 1m50000 1 ≤ a i ≤ 1 0 9 1\le a_i \le 10^9 1ai109 1 ≤ l 0 , r 0 ≤ n 1 \leq l_0, r_0 \leq n 1l0,r0n

思路

  1. 很明显是区间分块,预处理区间 1 ~ x 1\text{\textasciitilde} x 1~x 种类 k k k 的数量,和区间 l ~ r l\text{\textasciitilde}r l~r 里出现次数最多的种类;
  2. 由于种类编号十分大( 1 ≤ a i ≤ 1 0 9 1\le a_i \le 10^9 1ai109),需要离散化(可以不按种类编号大小)。
  3. 注意: 4 × 4 × 1 0 4 × 4 4 \times 4 \times 10^{4 \times 4} 4×4×104×4 Memory Limit Exceeded \text{Memory Limit Exceeded} Memory Limit Exceeded

代码

#include<bits/stdc++.h>
typedef int int32;
#define int long long
using namespace std;
const int N = 40000 + 5, M = 200 + 5;
int n, m, a[N], b[M][N], id[N], len, x, y, c[M][M], tot, cnt, d[N], last, e[N];
map<int, int>mp;
void init()
{
	len = sqrt(n);
	for (int i = 1; i <= n; i++)
	{
		if (i % len == 1)
		{
			cnt++;
			for (int i = 1; i <= tot; i++)
				b[cnt][i] = b[cnt - 1][i];
		}
		b[cnt][a[i]]++;
		id[i] = cnt;
	}
	for (int i = 1; i <= cnt; i++)
	{
		memset(e, 0, sizeof e);
		for (int j = 1; j < i; j++)
			c[i][j] = 1;
		for (int j = i; j <= cnt; j++)
		{
			int maxi = 1;
			for (int k = 1; k <= tot; k++)
			{
				e[k] += b[j][k] - b[j - 1][k];
				if (e[k] > e[maxi])
					maxi = k;
				else if (e[k] == e[maxi] && d[k] < d[maxi])
					maxi = k;
			}
			c[i][j] = maxi;
		}
	}
	return;
}
int find(int qx, int qy)
{
	int l = id[qx], r = id[qy], maxi = 1;
	memset(e, 0, sizeof e);
	if (id[qx - 1] != l && id[qy + 1] != r)
		return d[c[l][r]];
	if (r - l < 2)
	{
		for (int i = qx; i <= qy; i++)
		{
			e[a[i]]++;
			if (e[a[i]] > e[maxi])
				maxi = a[i];
			else if (e[a[i]] == e[maxi] && d[a[i]] < d[maxi])
				maxi = a[i];
		}
	}
	else
	{
		maxi = c[l + 1][r - 1];
		for (int i = qx; id[i] == l; i++)
		{
			e[a[i]]++;
			int tmp = e[a[i]] + b[r - 1][a[i]] - b[l][a[i]],
				pre = e[maxi] + b[r - 1][maxi] - b[l][maxi];
			if (tmp > pre)
				maxi = a[i];
			else if (tmp == pre && d[a[i]] < d[maxi])
				maxi = a[i];
		}
		for (int i = qy; id[i] == r; i--)
		{
			e[a[i]]++;
			int tmp = e[a[i]] + b[r - 1][a[i]] - b[l][a[i]],
				pre = e[maxi] + b[r - 1][maxi] - b[l][maxi];
			if (tmp > pre)
				maxi = a[i];
			else if (tmp == pre && d[a[i]] < d[maxi])
				maxi = a[i];
		}
	}
	return d[maxi];
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		if (mp[a[i]] == 0)
			mp[a[i]] = ++tot, d[tot] = a[i];
		a[i] = mp[a[i]];
	}
	init();
	while (m--)
	{
		cin >> x >> y;
		x = (x + last - 1) % n + 1;
		y = (y + last - 1) % n + 1;
		if (x > y)
			swap(x, y);
		last = find(x, y);
		cout << last << '\n';
	}
	return 0;
}
  • 31
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值