标签:ack lower SQ 代码 let lock tor str highlight
题目大意:
求区间众数,强制在线。
题解:
考虑分块,一段区间的众数一定在整块的众数和两边多出来的数中。
可能是众数的数有O(sqrt(n))个,然后我们考虑查询这些数在区间中出现了几次。
把原来的序列中相同数字的下边从小到大扔进vector中,然后二分就能求每个数在区间中出现了几次。
找一个出现次数最大的就行了。
复杂度O(nsqrt(n)log(n))
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
int id,n,m,block,ans,f[505][505],cnt[100005],v[100005],belong[1000005],val[1000005];
map<int,int> mp;
vector<int> vec[1000005];
void pre(int x){
memset(cnt,0,sizeof(cnt));
int maxx=0,ans=0;
for (int i=(x-1)*block+1; i<=n; i++){
cnt[v[i]]++;
int t=belong[i];
if (cnt[v[i]]>maxx || (cnt[v[i]]==maxx && val[v[i]]<val[ans])){
ans=v[i];
maxx=cnt[v[i]];
}
f[x][t]=ans;
}
}
int query(int l,int r,int x){
int t=upper_bound(vec[x].begin(),vec[x].end(),r)-lower_bound(vec[x].begin(),vec[x].end(),l);
return t;
}
int calc(int l,int r){
int ans=f[belong[l]+1][belong[r]-1];
int maxx=query(l,r,ans);
for (int i=l; i<=min(belong[l]*block,r); i++){
int x=query(l,r,v[i]);
if (x>maxx || (x==maxx && val[v[i]]<val[ans])) {
ans=v[i];
maxx=x;
}
}
if (belong[l]!=belong[r]){
for (int i=(belong[r]-1)*block+1; i<=r; i++){
int x=query(l,r,v[i]);
if (x>maxx || (x==maxx && val[v[i]]<val[ans])) {
ans=v[i];
maxx=x;
}
}
}
return ans;
}
int main(){
scanf("%d%d",&n,&m);
block=200;
int ans=0;
for (int i=1; i<=n; i++){
scanf("%d",&v[i]);
if (!mp[v[i]]){
mp[v[i]]=++id;
val[id]=v[i];
}
v[i]=mp[v[i]];
vec[v[i]].push_back(i);
}
for (int i=1; i<=n; i++)
belong[i]=(i-1)/block+1;
int cnt=(n-1)/block+1;
for (int i=1; i<=cnt; i++) pre(i);
for (int i=1; i<=m; i++){
int l,r;
scanf("%d%d",&l,&r);
l=(l+ans-1)%n+1,r=(r+ans-1)%n+1;
if (l>r) swap(l,r);
ans=val[calc(l,r)];
printf("%d\n",ans);
}
return 0;
}
:
标签:ack lower SQ 代码 let lock tor str highlight
原文地址:https://www.cnblogs.com/silenty/p/8877330.html