P5048 题解
吐槽:感觉本题最多紫。
考虑分块,设块长为 \(S\)。
离散化序列之后,设 \(f_{i,j}\) 表示第 \(i,i+1,\dots,j\) 块的众数出现次数,可以在 \(O((\dfrac{n}{S})^2\times S))=O(\dfrac{n^2}{S})\) 时间内预处理出来。
查询的时候先把整段的答案算出来,考虑零碎部分怎么算。
设目前算出的众数的出现数量为 \(ans\)。
此时传统的做法是值域分块查询这个数在一个区间中出现次数,但是我们要算的比这个弱很多,只要判断这个数在这个区间内出现次数为 \(ans+1\) 即可。
那我们只要对每个值开个 vector,按顺序维护这个值对应的所有下标,然后判断左边零碎时我们只要判断在右边 \(ans\) 个是否在 \([l,r]\) 中,判断右边零碎时我们只要判断在左边 \(ans\) 个是否在 \([l,r]\) 中即可。
时间复杂度 \(O(\dfrac{n^2}{S}+mS)\),空间复杂度 \(O(n)\)。
取 \(S=\dfrac{n}{\sqrt m}\) 可得复杂度为 \(O(n\sqrt m)\)。
一点也不卡常,习惯性开个论文鸽快读就过了。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct IO_Tp {
const static int _I_Buffer_Size = 2 << 23;
char _I_Buffer[_I_Buffer_Size], *_I_pos = _I_Buffer;
const static int _O_Buffer_Size = 2 << 23;
char _O_Buffer[_O_Buffer_Size], *_O_pos = _O_Buffer;
IO_Tp() { fread(_I_Buffer, 1, _I_Buffer_Size, stdin); }
~IO_Tp() { fwrite(_O_Buffer, 1, _O_pos - _O_Buffer, stdout); }
IO_Tp &operator>>(int &res) {
int f=1;
while (!isdigit(*_I_pos)&&(*_I_pos)!='-') ++_I_pos;
if(*_I_pos=='-')f=-1,++_I_pos;
res = *_I_pos++ - '0';
while (isdigit(*_I_pos)) res = res * 10 + (*_I_pos++ - '0');
res*=f;
return *this;
}
IO_Tp &operator<<(int n) {
if(n<0)*_O_pos++='-',n=-n;
static char _buf[10];
char *_pos = _buf;
do
*_pos++ = '0' + n % 10;
while (n /= 10);
while (_pos != _buf) *_O_pos++ = *--_pos;
return *this;
}
IO_Tp &operator<<(char ch) {
*_O_pos++ = ch;
return *this;
}
} IO;
const int N=500005,S=715;
int n,m,bl,num,a[N],b[N],L[S],R[S],f[S][S],tot[N],pl[N];
vector<int>v[N];
int query(int l,int r){
int ret=0;
if(b[l]==b[r]){
for(int i=l;i<=r;i++)ret=max(ret,++tot[a[i]]);
for(int i=l;i<=r;i++)tot[a[i]]=0;
return ret;
}
ret=f[b[l]+1][b[r]-1];
for(int i=l;i<=R[b[l]];i++)while(pl[i]+ret<v[a[i]].size()&&v[a[i]][pl[i]+ret]<=r)ret++;
for(int i=L[b[r]];i<=r;i++)while(pl[i]-ret>=0&&v[a[i]][pl[i]-ret]>=l)ret++;
return ret;
}
int main(){
IO>>n>>m;
for(int i=1;i<=n;i++)IO>>a[i],b[i]=a[i];
sort(b+1,b+n+1);
num=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+num+1,a[i])-b,pl[i]=v[a[i]].size(),v[a[i]].push_back(i);
bl=sqrt(n);
for(int i=1;i<=n;i++)b[i]=(i-1)/bl+1;
num=b[n];
for(int i=1;i<=num;i++)L[i]=R[i-1]+1,R[i]=i*bl;
R[num]=n;
for(int i=1;i<=num;i++){
memset(tot,0,sizeof(tot));
for(int j=i;j<=num;j++){
f[i][j]=f[i][j-1];
for(int k=L[j];k<=R[j];k++)f[i][j]=max(f[i][j],++tot[a[k]]);
}
}
memset(tot,0,sizeof(tot));
for(int lastans=0;m--;){
int l,r;
IO>>l>>r;
l^=lastans,r^=lastans;
IO<<(lastans=query(l,r))<<'\n';
}
return 0;
}