[Ynoi2019 模拟赛] Yuno loves sqrt technology III
Link
Prob
给你一个长为 \(n\) 的序列,\(m\) 次询问,每次查询一个区间的众数的出现次数,强制在线。
\(1\leq n,m\leq 5\times 10^5\)。
Time : 3000 ms
Memory : 62.5 MiB
Solution
-
对于端点在同一块的查询,直接暴力。
-
否则,和蒲公英一样,首先预处理块 \(i\) 到块 \(j\) 的众数 \(F_{i,j}\) 和 \(j\) 在前 \(i\) 块出现的次数 \(cnt_{i,j}\)。
由于众数只可能是 \(F_{block(l),block(r)}\) 或者散块中的数,所以只需考虑散块如何处理。我们对于每一个 \(i\),将 \(i\) push_back 进 \(a_i\) 所属的 vector 中,并记 \(p_i\) 为其下标。
对于左散块,检查
vector<int>[a[i]][p[i]+ans]<=r是否为真。若为真,ans++;否则检查下一个。重复执行。右边同理。
不卡常。
Code
Max Mem : 21.19 MiB
Average Time : 1106 ms
Length : 1.69 KiB
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+9;
const int S=7.1e2+9;
int a[N],n,m;
int blk[N],L[N],R[N],B;
int F[S][S],A[S][S],buc[N];
vector<int> pos[N];int p[N];
int val[N];map<int,int> mp;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
#define endl '\n'
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],val[i]=a[i];
sort(val+1,val+n+1);
int cnt=unique(val+1,val+n+1)-val-1;
for(int i=1;i<=cnt;i++) mp[val[i]]=i;
for(int i=1;i<=n;i++) a[i]=mp[a[i]];
B=ceil(sqrt(n));
for(int i=1;i<=n;i++) blk[i]=(i-1)/B+1;
for(int i=1;i<=blk[n];i++) L[i]=B*(i-1)+1,R[i]=B*i;R[blk[n]]=n;
for(int i=1;i<=n;i++) p[i]=pos[a[i]].size(),pos[a[i]].push_back(i);
for(int i=1;i<=blk[n];i++){
memset(buc,0,sizeof(buc));
for(int j=i;j<=blk[n];j++){
F[i][j]=F[i][j-1];
for(int k=L[j];k<=R[j];k++) F[i][j]=max(F[i][j],++buc[a[k]]);
}
}
memset(buc,0,sizeof(buc));
int lst=0;
while(m--){
int l,r;
cin>>l>>r;
l^=lst;r^=lst;
if(r<l) swap(l,r);
int ans=0;
if(blk[l]==blk[r]){
for(int i=l;i<=r;i++){
ans=max(ans,++buc[a[i]]);
}
for(int i=l;i<=r;i++) buc[a[i]]=0;
}else{
ans=F[blk[l]+1][blk[r]-1];
for(int i=l;i<=R[blk[l]];i++){
while(p[i]+ans<pos[a[i]].size()&&pos[a[i]][p[i]+ans]<=r) ans++;
}
for(int i=L[blk[r]];i<=r;i++){
while(p[i]-ans>=0&&pos[a[i]][p[i]-ans]>=l) ans++;
}
}
cout<<ans<<endl;
lst=ans;
}
return 0;
}

浙公网安备 33010602011771号