[Ynoi2019模拟赛]Yuno loves sqrt technology III

时间:2023-03-09 01:08:45
[Ynoi2019模拟赛]Yuno loves sqrt technology III

题目大意:

给你一个长为n的序列a,m次询问,每次查询一个区间的众数的出现次数,强制在线。

解题思路:

出题人题解

众所周知lxl是个毒瘤,Ynoi道道都是神仙题

首先得离散化。

分块后,预处理Fi,j表示第i∼j块的众数的出现次数。此处要用一个桶,空间复杂度O(n),时间复杂度O(n√n)。

用vector按顺序存每个数值所有元素的出现位置。

再记录每个元素在相应vector里的下标p。

以上空间复杂度都是O(n)的。

考虑询问,中间的直接使用预处理出的Fi,j的值即可。设当前的答案ans=Fi,j。

考虑边界的元素。

显然,由于边界的数最多2√n个,所以最多使得答案增加2√n。

我们只需要检查这些边角的元素,每次判断这些数的出现次数能否达到ans+1。

对于左边的边角元素x,我们在相应的vector里找到下标为px+ans的元素yy,若y⩽ry⩽r,则说明该数值在范围内有至少ans+1ans+1个数,暴力++ans即可。

对于右边的边角元素x,我们在相应的vector里找到下标为px−ans的元素yy,若y⩾ly⩾l,则说明该数值在范围内有至少ans+1ans+1个数,暴力++ans即可。

每次询问对O(√n)个元素检查,++ans的次数为O(√n)次。所以查询的时间复杂度为O(m√n)。

总时间复杂度O((n+m)√n),空间复杂度O(n),lxl说达到了下界。

C++ Code:

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
#define siz 708
#define N 500001
class istream{
char buf[],*s;
public:
inline istream(){
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
#endif
fread(s=buf,,,stdin);
fclose(stdin);
}
inline istream&operator>>(int&rhs){
int f=rhs=;
for(;!isdigit(*s);++s)f=*s=='-';
for(;isdigit(*s);)
rhs=(rhs<<)+(rhs<<)+(*s++^'');
if(f)rhs=-rhs;
return*this;
}
}cin;
class ostream{
char buf[],*s;
public:
inline ostream(){s=buf;}
inline ostream&operator<<(int rhs){
if(rhs<)*s++='-',rhs=-rhs;
if(rhs==){
*s++='';
return*this;
}
static int w;
for(w=;w<=rhs;w*=);
for(w/=;w;w/=)*s++=(rhs/w)^'',rhs%=w;
return*this;
}
inline ostream&operator<<(const char&rhs){*s++=rhs;return*this;}
inline~ostream(){
fwrite(buf,,s-buf,stdout);
}
}cout;
int n,m,L[],R[],bel[N],blocks,mx[][],ans,tot[N],wz[N],a[N];
void init(){
blocks=(n-)/siz+;
for(int i=;i<=blocks;++i)L[i]=R[i-]+,R[i]=i*siz;
R[blocks]=n;
for(int i=;i<=blocks;++i){
memset(tot,,sizeof tot);
for(int j=L[i];j<=R[i];++j)bel[j]=i;
for(int j=i;j<=blocks;++j){
int&F=mx[i][j];
F=mx[i][j-];
for(int k=L[j];k<=R[j];++k)
F=std::max(F,++tot[a[k]]);
}
}
}
std::vector<int>ls,v[N];
int main(){
ls.push_back(-);
cin>>n>>m;
for(int i=;i<=n;ls.push_back(a[i++]))cin>>a[i];
std::sort(ls.begin(),ls.end());
ls.erase(std::unique(ls.begin(),ls.end()),ls.end());
for(int i=;i<=n;++i)v[a[i]=std::lower_bound(ls.begin(),ls.end(),a[i])-ls.begin()].push_back(i),wz[i]=v[a[i]].size()-;
init();
memset(tot,,sizeof tot);
while(m--){
int l,r;cin>>l>>r;
l^=ans,r^=ans;
ans=;
if(bel[l]==bel[r]){
for(int i=l;i<=r;++i)ans=std::max(ans,++tot[a[i]]);
for(int i=l;i<=r;++i)tot[a[i]]=;
}else{
ans=mx[bel[l]+][bel[r]-];
for(int i=l;i<=R[bel[l]];++i){
int it=wz[i];
while(it+ans<v[a[i]].size()&&v[a[i]][it+ans]<=r)++ans;
}
for(int i=L[bel[r]];i<=r;++i){
int it=wz[i];
while(it-ans>=&&v[a[i]][it-ans]>=l)++ans;
}
}
cout<<ans<<'\n';
}
return ;
}