[Ynoi2019 模拟赛] Yuno loves sqrt technology III
\(\text{Problem}:\)题目链接
\(\text{Solution}:\)
区间众数,强制在线。大力分块。
考虑预处理 \(cnt_{L,R}\),表示整块区间 \([L,R]\) 的答案。这部分的时间复杂度为 \(O(nB)\)
对 \(a_{i}\) 离散化,预处理 \(g_{i,j}\) 表示 \(i\) 这个数第 \(j\) 次在序列中出现的位置(从前到后),\(h_{i}\) 表示 \(a_{i}\) 在 \(i\) 这个位置是第几次出现。
对于查询 \([l,r]\),首先取整块的答案,记为 \(res\)。对于左散块中的每一个 \(a_{i}\),如果 \(g_{a_{i},h_{i}+res}\leq r\),那么 \(res\) 可以增加。对于右散块也类似,只需 \(g_{a_{i},h_{i}-res}\geq l\) 即可。
总时间复杂度 \(O(\cfrac{n^{2}}{B}+nB)\)。当 \(B=\sqrt n\) 时,时间复杂度为 \(O(n\sqrt n)\),可以通过本题。
注意本题较为卡常。
\(\text{Code}:\)
#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=500010, B=810;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,m,a[N],ta[N],pp,lsta,cnt[B][B];
vector<int> g[N]; int h[N];
int blk,bl[N],tot[N],pre[N];
signed main()
{
n=read(), m=read();
for(ri int i=1;i<=n;i++) a[i]=ta[i]=read();
sort(ta+1,ta+1+n);
int pp=unique(ta+1,ta+1+n)-ta-1;
for(ri int i=1;i<=n;i++)
{
a[i]=lower_bound(ta+1,ta+1+pp,a[i])-ta;
h[i]=(int)g[a[i]].size();
g[a[i]].eb(i);
}
blk=666;
for(ri int i=1;i<=n;i++) bl[i]=(i-1)/blk+1;
for(ri int i=1;i<=bl[n];i++)
{
memset(tot,0,sizeof(tot));
for(ri int j=i;j<=bl[n];j++)
{
int l=(j-1)*blk+1, r=min(j*blk,n);
cnt[i][j]=cnt[i][j-1];
for(ri int k=l;k<=r;k++) tot[a[k]]++, cnt[i][j]=max(cnt[i][j],tot[a[k]]);
}
}
memset(tot,0,sizeof(tot));
for(ri int i=1;i<=m;i++)
{
int l=read(), r=read();
l^=lsta, r^=lsta;
if(l>n) l%=n;
if(r>n) r%=n;
if(l>r) swap(l,r);
if(bl[l]==bl[r])
{
int res=0;
for(ri int j=l;j<=r;j++)
{
tot[a[j]]++;
res=max(res,tot[a[j]]);
}
printf("%d\n",lsta=res);
for(ri int j=l;j<=r;j++) tot[a[j]]--;
continue;
}
int L=bl[l], R=bl[r];
int res=cnt[L+1][R-1];
for(ri int j=l;j<=L*blk;j++)
{
if(!pre[a[j]]) pre[a[j]]=j;
int x=pre[a[j]];
while(h[x]+res<(int)g[a[j]].size()&&g[a[j]][h[x]+res]<=r) res++;
}
for(ri int j=l;j<=L*blk;j++) pre[a[j]]=0;
for(ri int j=r;j>=(R-1)*blk+1;j--)
{
if(!pre[a[j]]) pre[a[j]]=j;
int x=pre[a[j]];
while(h[x]-res>=0&&g[a[j]][h[x]-res]>=l) res++;
}
for(ri int j=(R-1)*blk+1;j<=r;j++) pre[a[j]]=0;
printf("%d\n",lsta=res);
}
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。