呃,这算是我自己做出来的第一道黑题吧。。。
感觉巨水虽然我吸氧才过QAQ
来一波题解~
分块板子题
1.题意及思路
首先,发现题目是要求静态区间众数
暴力的想法:
先离散化,对于每个询问区间\([l,r]\) ,开一个桶,然后暴扫,复杂度\(O(n\times m)\),TLE
那么可以考虑用线段树等
但是显然众数不满足区间可加性
所以考虑分块算法
虽然复杂度更劣,但代码简单
2.分块正解
将整个区间分为\(T\)个块,每块长 \(len\)
那么询问\([l,r]\) 必然包括三个部分
即两端的零散区间和中间整段区间
那么众数的来源也就对应的只有三种情况
废话,不然呢!
到这里,我们的复杂度仍然是假的
因为每次都要将整个询问区间扫一遍
那么此时分块的优势就体现出来了
将询问区间分成三块后,分别处理:
1.左边零散区间:暴力扫,复杂度\(O(len)\)
2.右边零散区间:同上
3.中间整块区间:
我们可以预处理出一个数组\(color[L][R][N]\)做到每次询问时\(O(1)\)
其中\(L,R\)是表示左右端点块(即当前区间\([l,r]=[L*len+1,R*len]\))
\(N\)表示哪种颜色
那么\(color[L][R][K]=color[L][R-1][K]+\sum_{i=(R-1)*len+1}^{R*len}[a[i]==K]\)
所以预处理的复杂度是\(O(N*T^2)\)
那么总共的复杂度就是\(O(N*T*T+M*N/T)\)
可以发现当\(T=N^\frac{1}{3}\) 时最优
3.代码
#include<bits/stdc++.h>
#define il inline
#define RG register int
#define ll long long
#define gc getchar
using namespace std;
il int rd()
{
int x=0,flag=1;
char ch=0;
while((ch>'9'||ch<'0')&&ch!='-')ch=gc();
if(ch=='-')flag=-1,ch=gc();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=gc();
return x*flag;
}
const int MAXT=40,MAXN=40010;
int color[MAXT][MAXT][MAXN];
int modenum[MAXT][MAXT],mdtimes[MAXT][MAXT];
int n,m,T,len;
int a[MAXN],b[MAXN];
int l,r,ans,ans2;
int main ()
{
//freopen("in","r",stdin);
//freopen("out","w",stdout);
n=rd();m=rd();
T=floor(pow(n,0.3333333));
len=n/T;
for(RG i=1;i<=n;i++)
b[i]=a[i]=rd();
sort(b+1,b+n+1);
unique(b+1,b+n+1);
for(RG i=1;i<=n;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
for(RG i=1;i<=T;i++)
for(RG j=i;j<=T;j++){
for(RG k=1;k<=n;k++)
color[i][j][k]+=color[i][j-1][k];
for(RG k=(j-1)*len+1;k<=j*len;k++)
color[i][j][a[k]]++;
for(RG k=1;k<=n;k++)
if(mdtimes[i][j]<color[i][j][k])modenum[i][j]=k,mdtimes[i][j]=color[i][j][k];
}
for(RG i=1;i<=m;i++){
l=rd(),r=rd();
l=(l+b[ans2]-1)%n+1,r=(r+b[ans2]-1)%n+1;
if(l>r)swap(l,r);
int L=l/len+1,R=(r-1)/len;
ans2=modenum[L+1][R];//?
if(L<=R)
{
for(RG j=l;j<=L*len;j++)
color[L+1][R][a[j]]++;
for(RG j=R*len+1;j<=r;j++)
color[L+1][R][a[j]]++;
for(RG j=l;j<=L*len;j++)
if(color[L+1][R][a[j]]>color[L+1][R][ans2]||(color[L+1][R][a[j]]==color[L+1][R][ans2]&&ans2>a[j]))ans2=a[j];
for(RG j=R*len+1;j<=r;j++)
if(color[L+1][R][a[j]]>color[L+1][R][ans2]||(color[L+1][R][a[j]]==color[L+1][R][ans2]&&ans2>a[j]))ans2=a[j];
for(RG j=l;j<=L*len;j++)
color[L+1][R][a[j]]--;
for(RG j=R*len+1;j<=r;j++)
color[L+1][R][a[j]]--;
printf("%d\n",b[ans2]);
}
else
{
for(RG j=l;j<=r;j++)
color[L+1][R][a[j]]++;
for(RG j=l;j<=r;j++)
if(color[L+1][R][a[j]]>color[L+1][R][ans2]||(color[L+1][R][a[j]]==color[L+1][R][ans2]&&ans2>a[j]))ans2=a[j];
for(RG j=l;j<=r;j++)
color[L+1][R][a[j]]--;
printf("%d\n",b[ans2]);
}
}
return 0;
}