链接
http://www.lydsy.com/JudgeOnline/problem.php?id=2724
题解
日常抄题解…
抄了黄学长的题解,
f[i][j]
表示第
i
个块到第
对于一次询问
[l,r]
,显然能够成为众数的数,要么是
[l,r]
所包含的那些完整块的众数,要么是两边多出来的那些数里的某个数。
上述数的数量级别是
O(N−−√)
的。
显然我们要对这O(\sqrt{N})
个数统计每个数在
[l,r]
中的出现次数,然后比较一下就能出结果,显然可以直接主席树。但是黄学长用了
vector
,他把每个数开个
vector$,然后在上上面二分,也挺快的还好写。
代码
//分块
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#define maxn 50000
#define maxs 240
using namespace std;
int lastans, cnt[maxn], tmp[maxn], a[maxn], f[maxs][maxs], size, N, M;
vector<int> v[maxn];
void init()
{
int i, j, ans;
scanf("%d%d",&N,&M); size=sqrt(N);
for(i=1;i<=N;i++)scanf("%d",a+i),tmp[i]=a[i];
sort(tmp+1,tmp+N+1);
for(i=1;i<=N;i++)a[i]=lower_bound(tmp+1,tmp+N+1,a[i])-tmp, v[a[i]].push_back(i);
for(i=1;i<=N;i=(i/size+1)*size)
{
for(j=1;j<=N;j++)cnt[j]=0;
ans=0;
for(j=i;j<=N;j++)
{
cnt[a[j]]++;
if(cnt[a[j]]==cnt[ans])ans=min(ans,a[j]);
if(cnt[a[j]]>cnt[ans])ans=a[j];
if(j%size==size-1)f[i/size][j/size]=ans;
}
}
}
int find(int w, int L, int R)
{
int l, r, mid, t;
for(l=0,r=v[w].size()-1;l<r;)
{
mid=(l+r)>>1;
if(v[w][mid]<L)l=mid+1;
else r=mid;
}
t=l;
for(l=0,r=v[w].size()-1;l<r;)
{
mid=(l+r+1)>>1;
if(v[w][mid]>R)r=mid-1;
else l=mid;
}
return l-t+1;
}
void q(int l, int r)
{
int i, ans=f[l/size+1][r/size-1], t=ans;
if(ans)cnt[ans]=find(ans,l,r);
for(i=l;i/size==l/size and i<=r;i++)
{
cnt[a[i]]=find(a[i],l,r);
if(cnt[a[i]]==cnt[ans])ans=min(ans,a[i]);
if(cnt[a[i]]>cnt[ans])ans=a[i];
}
for(i=r;i/size==r/size and i>=l;i--)
{
cnt[a[i]]=find(a[i],l,r);
if(cnt[a[i]]==cnt[ans])ans=min(ans,a[i]);
if(cnt[a[i]]>cnt[ans])ans=a[i];
}
cnt[t]=0;
for(i=l;i/size==l/size and i<=r;i++)cnt[a[i]]=0;
for(i=r;i/size==r/size and i>=l;i--)cnt[a[i]]=0;
printf("%d\n",lastans=tmp[ans]);
}
int main()
{
int l, r;
init();
while(M--)
{
scanf("%d%d",&l,&r);
l=(l+lastans-1)%N+1, r=(r+lastans-1)%N+1;
if(l>r)swap(l,r);
q(l,r);
}
return 0;
}