标签:时间 back 中间 sqrt OLE 区间 inline set swa
前几天刚学习了分块,感觉这道题用分块求解的方式挺巧妙的
既然用的是分块,那么肯定是两端暴力求解,中间要快速地处理每个块
首先我们要得到一个结论,最后求出的这一个众数必定为中间块的众数或者是两端的任意一个数,那么我们用\(nu[i][j]\)来表示第\(i\)个块到第\(j\)个块的众数,我们可以用用\(O(n\sqrt{n})\)的时间复杂度,先枚举每个块,然后枚举后面的点来求出\(nu[i][j]\),放一下这一段的代码
void pre(int x)
{
memset(cnt,0,sizeof(cnt));
int maxx=0,num1=0;
for(int i=(x-1)*m+1;i<=n;i++)
{
cnt[a[i]]++;
if(cnt[a[i]]>maxx||(cnt[a[i]]==maxx&&a[i]<num1))
maxx=cnt[a[i]],num1=a[i];
nu[x][pos[i]]=num1;
}
}
接下来就是每一次的询问,先假定中间的块的众数为整个区间的众数,并求出在区间内的个数,再枚举两端的每一个点,求出在区间内的个数,如果比之前的多那么就更新
至于求一个数在区间内的个数,我们可以巧用\(vector\),记录每个数字出现的位置,然后用upper_bound和lower_bound求出在区间内的个数
记得离散化!
#include<bits/stdc++.h>
using namespace std;
int n,a[100003],num[100003],id,pos[100003],l,r,su,cnt[100003],nu[3003][3003],res,m,b[100003],las,o;
vector<int>l1[100003];
map<int,int>mp;
int ask1(int ll,int rr,int x)
{
return upper_bound(l1[x].begin(),l1[x].end(),rr)-lower_bound(l1[x].begin(),l1[x].end(),ll); //求出一个数在区间内的个数
}
void pre(int x) //预处理nu[i][j]
{
memset(cnt,0,sizeof(cnt));
int maxx=0,num1=0;
for(int i=(x-1)*m+1;i<=n;i++)
{
cnt[a[i]]++;
if(cnt[a[i]]>maxx||(cnt[a[i]]==maxx&&a[i]<num1))
maxx=cnt[a[i]],num1=a[i];
nu[x][pos[i]]=num1;
}
}
int ask(int l1,int r1)
{
int maxx=0,num1=0;
if(pos[l1]+1<pos[r1])
maxx=ask1(l1,r1,nu[pos[l1]+1][pos[r1]-1]),num1=nu[pos[l1]+1][pos[r1]-1]; //假定众数为中间的块的众数
for(int i=l1;i<=min(r1,pos[l1]*m);i++) //枚举左端的块
{
res=ask1(l1,r1,a[i]);
if(res>maxx||(res==maxx&&a[i]<num1))
maxx=res,num1=a[i];
}
if(pos[l1]!=pos[r1]) //枚举右端的块
for(int i=(pos[r1]-1)*m+1;i<=r1;i++)
{
res=ask1(l1,r1,a[i]);
if(res>maxx||(res==maxx&&a[i]<num1))
maxx=res,num1=a[i];
}
return num[num1];
}
int main()
{
scanf("%d%d",&n,&o);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
if(!mp[b[i]])
id++,mp[b[i]]=id,num[id]=b[i]; //离散化
for(int i=1;i<=n;i++)
a[i]=mp[a[i]],l1[a[i]].push_back(i);
for(int i=1;i<=id;i++)
l1[i].push_back(n+1);
m=pow(n,0.4);
for(int i=1;i<=n;i++)
pos[i]=(i-1)/m+1;
su=pos[n];
for(int i=1;i<=su;i++)
pre(i);
for(int i=1;i<=o;i++)
{
scanf("%d%d",&l,&r);
l=(l+las-1)%n+1,r=(r+las-1)%n+1;
if(l>r)
swap(l,r);
las=ask(l,r);
cout<<las<<endl;
}
return 0;
}
标签:时间 back 中间 sqrt OLE 区间 inline set swa
原文地址:https://www.cnblogs.com/dzice/p/12195959.html