[Ynoi2019 模拟赛] Yuno loves sqrt technology III

\(\text{Problem}:\)题目链接

\(\text{Solution}:\)

区间众数,强制在线。大力分块。

考虑预处理 \(cnt_{L,R}\),表示整块区间 \([L,R]\) 的答案。这部分的时间复杂度为 \(O(nB)\)

\(a_{i}\) 离散化,预处理 \(g_{i,j}\) 表示 \(i\) 这个数第 \(j\) 次在序列中出现的位置(从前到后),\(h_{i}\) 表示 \(a_{i}\)\(i\) 这个位置是第几次出现。

对于查询 \([l,r]\),首先取整块的答案,记为 \(res\)。对于左散块中的每一个 \(a_{i}\),如果 \(g_{a_{i},h_{i}+res}\leq r\),那么 \(res\) 可以增加。对于右散块也类似,只需 \(g_{a_{i},h_{i}-res}\geq l\) 即可。

总时间复杂度 \(O(\cfrac{n^{2}}{B}+nB)\)。当 \(B=\sqrt n\) 时,时间复杂度为 \(O(n\sqrt n)\),可以通过本题。

注意本题较为卡常。

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=500010, B=810;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,a[N],ta[N],pp,lsta,cnt[B][B];
vector<int> g[N]; int h[N];
int blk,bl[N],tot[N],pre[N];
signed main()
{
	n=read(), m=read();
	for(ri int i=1;i<=n;i++) a[i]=ta[i]=read();
	sort(ta+1,ta+1+n);
	int pp=unique(ta+1,ta+1+n)-ta-1;
	for(ri int i=1;i<=n;i++)
	{
		a[i]=lower_bound(ta+1,ta+1+pp,a[i])-ta;
		h[i]=(int)g[a[i]].size();
		g[a[i]].eb(i);
	}
	blk=666;
	for(ri int i=1;i<=n;i++) bl[i]=(i-1)/blk+1;
	for(ri int i=1;i<=bl[n];i++)
	{
		memset(tot,0,sizeof(tot));
		for(ri int j=i;j<=bl[n];j++)
		{
			int l=(j-1)*blk+1, r=min(j*blk,n);
			cnt[i][j]=cnt[i][j-1];
			for(ri int k=l;k<=r;k++) tot[a[k]]++, cnt[i][j]=max(cnt[i][j],tot[a[k]]);
		}
	}
	memset(tot,0,sizeof(tot));
	for(ri int i=1;i<=m;i++)
	{
		int l=read(), r=read();
		l^=lsta, r^=lsta;
		if(l>n) l%=n;
		if(r>n) r%=n;
		if(l>r) swap(l,r);
		if(bl[l]==bl[r])
		{
			int res=0;
			for(ri int j=l;j<=r;j++)
			{
				tot[a[j]]++;
				res=max(res,tot[a[j]]);
			}
			printf("%d\n",lsta=res);
			for(ri int j=l;j<=r;j++) tot[a[j]]--;
			continue;
		}
		int L=bl[l], R=bl[r];
		int res=cnt[L+1][R-1];
		for(ri int j=l;j<=L*blk;j++)
		{
			if(!pre[a[j]]) pre[a[j]]=j;
			int x=pre[a[j]];
			while(h[x]+res<(int)g[a[j]].size()&&g[a[j]][h[x]+res]<=r) res++;
		}
		for(ri int j=l;j<=L*blk;j++) pre[a[j]]=0;
		for(ri int j=r;j>=(R-1)*blk+1;j--)
		{
			if(!pre[a[j]]) pre[a[j]]=j;
			int x=pre[a[j]];
			while(h[x]-res>=0&&g[a[j]][h[x]-res]>=l) res++;
		}
		for(ri int j=(R-1)*blk+1;j<=r;j++) pre[a[j]]=0;
		printf("%d\n",lsta=res);
	}
	return 0;
}
posted @ 2021-03-01 15:12  zkdxl  阅读(54)  评论(0编辑  收藏  举报