嗯,今天也是我第一次学分块,所以更下题解和分块.辛格大佬说这个题就是莫队的板子
分块一般是将一个区间分成sqrt(n)块,然后对于进行处理,比如说今天我们这个题目求区间众数.
我们处理出两个数组,一个f[i][j]表示第i块到第j块的众数是多少,另外一个s[i][j]表示前i块中j出现次数.处理完这两个数组,我们就很容易知道假如给定一个区间l-r要我们求这个区间的众数,怎么求呢?假设l-r不跨一个区间.那么直接暴力求就好了,假如跨的区间>1,那么众数产生会是哪些地方呢?无非出现在两边边界.
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N=4e4+5;
const int M=2e2+10;
int a[N],b[N];//a数组用来存值,b数组用来离散化
int f[M][M],s[M][N];//f数组是用来存第i块到第j块的众数,s数组是用来存前i块中值为j的数量有多少.
int to[N],block,cnt;//开个桶数组.块的大小.块的数量
inline int ask(int x)//查询x在哪一块.
{
return (x-1)/block+1;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);//m组查询.
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);//输入
b[i]=a[i];
}
block=(int)sqrt(n);//块的大小
cnt=(n-1)/block+1;//块的数量
sort(a+1,a+1+n);
int sum=unique(a+1,a+1+n)-a-1;
for(int i=1;i<=n;i++)//离散化
{
b[i]=lower_bound(a+1,a+1+sum,b[i])-a;
}
for(int i=1;i<=cnt;i++)//处理s数组
{
for(int j=(i-1)*block+1;j<=min(n,i*block);j++)
{
s[i][b[j]]++;
}
for(int j=1;j<=sum;j++)
{
s[i][j]+=s[i-1][j];
}
}
int mx;//众数
for(int i=1;i<=cnt;i++)//处理f数组
{
for(int j=i;j<=cnt;j++)
{
mx=f[i][j-1];//没选肯定众数是上一个区间的众数.
for(int k=(j-1)*block+1;k<=min(n,j*block);k++)
{
if(s[j][b[k]]-s[i-1][b[k]]>s[j][mx]-s[i-1][mx]||(s[j][b[k]]-s[i-1][b[k]]==s[j][mx]-s[i-1][mx]&&b[k]<mx))
{
mx=b[k];
}
}
f[i][j]=mx;
}
}
int ans=0,_l,_r;
while(m--)
{
scanf("%d%d",&_l,&_r);
int l=(_l+a[ans]-1)%n+1;
int r=(_r+a[ans]-1)%n+1;
if(l>r) swap(l,r);
if(ask(r)-ask(l)<=1)
{
for(int i=l;i<=r;i++)
{
to[b[i]]++;
}
for(int i=l;i<=r;i++)
{
if(to[b[i]]>to[ans]||(to[b[i]]==to[ans]&&b[i]<ans))
{
ans=b[i];
}
}
for(int i=l;i<=r;i++) to[b[i]]=0;
}
else
{
int bl=ask(l);
int br=ask(r);
ans=f[bl+1][br-1];//中间是众数.
for(int i=l;i<=bl*block;i++) to[b[i]]++;
for(int i=(br-1)*block+1;i<=r;i++) to[b[i]]++;
for(int i=l;i<=bl*block;i++)
{
if((to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]>to[ans]+s[br-1][ans]-s[bl][ans])||(to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]==to[ans]+s[br-1][ans]-s[bl][ans]&&b[i]<ans))
{
ans=b[i];
}
}
for(int i=(br-1)*block+1;i<=r;i++)
{
if((to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]>to[ans]+s[br-1][ans]-s[bl][ans])||(to[b[i]]+s[br-1][b[i]]-s[bl][b[i]]==to[ans]+s[br-1][ans]-s[bl][ans]&&b[i]<ans))
{
ans=b[i];
}
}
//清空
for(int i=l;i<=bl*block;i++) to[b[i]]=0;
for(int i=(br-1)*block+1;i<=r;i++) to[b[i]]=0;
}
cout<<a[ans]<<endl;
}
return 0;
}
友情提示下两个易错点,注意是对离散化之前答案取模而不是之后的答案,以及分块的中间块的处理..
很棒很棒,大佬加油!