1. 程式人生 > 其它 >LG P4168 [Violet]蒲公英

LG P4168 [Violet]蒲公英

\(\text{Problem}\)

強制線上靜態詢問區間眾數

\(\text{Solution}\)

不得不說 \(vector\) 是真的慢
\(LOJ\) 數列分塊入門 \(9\) 卡時間卡了兩個小時沒成功
說說夠快得做法
對原數列分塊
考慮已經預處理出任意兩塊之間得答案
散塊中出現的顏色可以讓其在整塊中失敗後翻盤
其它顏色就沒機會了
也就是說只考慮散塊中出現的顏色和整塊預處理出的答案
暴力掃散塊,再加上它在整塊中的個數就是它的出現次數,取最大值即可
達成此點還需維護每種顏色在塊中的字首和
在考慮預處理,參考詢問方法把塊 \(i\)\(j\) 的答案看成塊 \(i\)\(j-1\)

再多了第 \(j\)
於是完成

\(\text{Code}\)

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define re register
using namespace std;

const int N = 1e5 + 5;
int n, m, lst, st[N], ed[N], id[N], a[N], b[N], f[401][401], buc[N], PreSum[N][401];

inline int Count(int c, int l, int r){return PreSum[c][r] - PreSum[c][l - 1];}
inline void Prework()
{
	sort(b + 1, b + n + 1);
	int num = sqrt(n) + 1, len = unique(b + 1, b + n + 1) - b - 1;
	for(re int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + len + 1, a[i]) - b;
	for(re int i = 1; i <= num; i++)
	{
		st[i] = ed[i - 1] + 1, ed[i] = (i == num ? n : ed[i - 1] + n / num);
		for(re int j = 1; j <= len; j++) PreSum[j][i] = PreSum[j][i - 1];
		for(re int j = st[i]; j <= ed[i]; j++) id[j] = i, ++PreSum[a[j]][i];
	}
	for(re int i = 1; i <= num; i++)
		for(re int j = i; j <= num; j++)
		{
			int cl = 0, num = 0, nu;
			for(re int k = st[j]; k <= ed[j]; k++)
			{
				nu = Count(a[k], i, j);
				if (nu > num) num = nu, cl = a[k];
				else if (nu == num) cl = min(cl, a[k]);
			}
			if (i ^ j)
			{
				nu = Count(f[i][j - 1], i, j);
				if (nu > num) num = nu, cl = f[i][j - 1];
				else if (nu == num) cl = min(cl, f[i][j - 1]);
			}
			f[i][j] = cl;
		}
}
inline int Query(int l, int r)
{
	int x = id[l], y = id[r];
	if (x == y)
	{
		int cl = 0, num = 0, cnt = 0, nu;
		for(re int k = l; k <= r; ++buc[a[k]], k++);
		for(re int k = l; k <= r; k++)
		{
			nu = buc[a[k]], buc[a[k]] = 0;
			if (nu > num) num = nu, cl = a[k];
			else if (nu == num) cl = min(cl, a[k]);
		}
		return b[cl];
	}
	int cl = f[x + 1][y - 1], num = Count(cl, x + 1, y - 1), nu, cnt = 0;
	for(re int k = l; k <= ed[x]; ++buc[a[k]], k++);
	for(re int k = st[y]; k <= r; ++buc[a[k]], k++);
	for(re int k = l; k <= ed[x]; k++)
	{
		nu = buc[a[k]] + Count(a[k], x + 1, y - 1), buc[a[k]] = 0;
		if (nu > num) num = nu, cl = a[k];
		else if (nu == num) cl = min(cl, a[k]);
	}
	for(re int k = st[y]; k <= r; k++)
	{
		nu = buc[a[k]] + Count(a[k], x + 1, y - 1), buc[a[k]] = 0;
		if (nu > num) num = nu, cl = a[k];
		else if (nu == num) cl = min(cl, a[k]);
	}
	return b[cl];
}

inline void read(int &x)
{
	x = 0; char ch = getchar(); int f = 1;
	for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
	for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
	if (f - 1) x = ~x + 1;
}

int main()
{
	read(n), read(m);
	for(re int i = 1; i <= n; i++) read(a[i]), b[i] = a[i];
	Prework();
	for(re int l, r; m; --m)
	{
		read(l), read(r), l = (l + lst - 1) % n + 1, r = (r + lst - 1) % n + 1;
		if (l > r) swap(l, r);
		printf("%d\n", lst = Query(l, r));
	}
}