【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;
}

浙公网安备 33010602011771号