【Ynoi2019】Yuno loves sqrt technology III

【Ynoi2019】Yuno loves sqrt technology III

by AmanoKumiko

Description

给出长为\(n\)的序列\(a\)\(m\)次询问一个区间众数的出现次数

强制在线

Input

第一行两个数\(n,m\)

然后一行\(n\)个数读入\(a\)

然后\(m\)行每行两个数\(l,r\)读入询问

Output

输出\(m\)

每行一个数表示答案

Sample Input

4 1
2 3 3 3
2 4

Sample Output

3

Data Constraint

\(1\le n,m\le 5*10^5,0\le a_i\le 10^9\)

Solution

一道喵喵题

首先我们转化一下

变成询问区间最大出现次数

可以想到一个序列分块做法

我们设\(Max_{i,j}\)表示第\(i\)到第\(j\)块的最大出现次数

然后记\(S_{i,j}\)表示前\(i\)块,数\(j\)的出现次数

两者都可以\(O(n\sqrt n)\)预处理

查询时暴力加入,也是\(O(n\sqrt n)\)

但是有一个问题

这题的空间只够线性

你考虑这样一件事,就是说

对于当前的答案\(ans\),枚举散块加入时,每次的增量都是\(O(1)\)

那么假设当前这个数是这种数的第\(i\)个,只需第\(i+ans\)个也在这个区间内就行了

记录下每个数的排名,然后\(vector\)保存每种数

于是我们成功解决了这道题

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 500010
#define M 800

unordered_map<int,int>v;
vector<int>pos[N];
int n,B,sz,m,a[N],L[N],R[N],be[N],Max[M][M],tmp[N],cnt,id[N],ans,num[N];

int main(){
	scanf("%d%d",&n,&m);
	B=sqrt(n)+1;sz=n/B+1;
	F(i,1,sz){
		L[i]=R[i-1]+1;R[i]=min(n,L[i]+B-1);
		F(j,L[i],R[i])be[j]=i;
	}
	F(i,1,n){
		scanf("%d",&a[i]);
		if(v.find(a[i])==v.end())v[a[i]]=++cnt;
		id[i]=v[a[i]];
		pos[id[i]].push_back(i);
		num[i]=pos[id[i]].size();
	}
	F(i,1,sz){
		F(j,i,sz){
			Max[i][j]=Max[i][j-1];
			F(k,L[j],R[j]){
				tmp[id[k]]++;
				Max[i][j]=max(Max[i][j],tmp[id[k]]);
			}
		}
		memset(tmp,0,sizeof(tmp));
	}
	F(i,1,m){
		int l,r;
		scanf("%d%d",&l,&r);
		l^=ans;r^=ans;
		if(be[l]==be[r]){
			ans=0;
			F(j,l,r)tmp[id[j]]++,ans=max(ans,tmp[id[j]]);
			F(j,l,r)tmp[id[j]]=0;
			printf("%d\n",ans);
		}else{
			ans=max(0,Max[be[l]+1][be[r]-1]);
			Fd(j,R[be[l]],l)if(num[j]+ans<=pos[id[j]].size()){
				if(l<=pos[id[j]][num[j]+ans-1]&&pos[id[j]][num[j]+ans-1]<=r)ans++;
			}
			F(j,L[be[r]],r)if(num[j]-ans-1>=0){
				if(l<=pos[id[j]][num[j]-ans-1]&&pos[id[j]][num[j]-ans-1]<=r)ans++;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}
posted @ 2022-08-04 10:56  冰雾  阅读(28)  评论(0编辑  收藏  举报