这个题原来是黑题的说
来写点清(fei)新(chang)一(du)点(liu)的分块题吧...
一句话题意:求区间众数,强制在线。
好像还有在线莫队的做法......不会 Orz
众数这玩意儿不怎么好合并,所以考虑暴力分块。
设每块的大小为\(t\),我们维护三个东西
- \(cc[i][j]\)表示前\(i\)个块中,元素\(j\)出现了多少次(当然要离散化辣~~)
- \(ansv[i][j]\)第\(i\)个块到第\(j\)个块内的众数
- \(ansc[i][j]\)第\(i\)个块到第\(j\)个块内众数的出现次数
考虑怎么算这三个东西,\(cc\)的话\(O(n/t)\)的扫一遍所有的块,然后每次\(O(t)\)遍历块中元素就好了,复杂度为\(O(n/t^2)\)
\(ansv[i][j]\)和\(ansc[i][j]\),枚举\(i\),然后在从左到右枚举\(j\)的时候遍历第\(j\)个块内的所有元素,随便开个桶算一下,复杂度\(O((n/t)^2\times t)=O(n^2/t)\)
于是预处理的复杂度就是\(O(n^2/t)\)的
考虑查询区间\([l,r]\)的答案,如果\(l,r\)在同一块中直接暴力就好了。
如果不在假设第\(bl\)块到第\(br\)块被区间\([l,r]\)完全包含,刚开始的答案就是\(ansc[bl][br]\),然后枚举边角块的元素,维护个桶,更新答案即可。
因为\(n,m\)同阶,这里就用\(n\)好了,回答的总复杂度是\(O(2tn)\)
这样总复杂度就是\(n^2/t+2tn\),考虑\(t\)的取值。
令\(f(x)=n^2/x+2nx\),求导得到\(f'(x)=2n-n^2x^{-2}\),当\(f'(x)=0\)时,解得\(x=(n/2)^{1/2}\)。
取\(t=(n/2)^{1/2}\)的时候就能得到一个较优的复杂度,大概是\(O(n^{\frac{3}{2}})\)。
\(Code\)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;++i)
#define per(i,a,n) for (int i=n-1;i>=a;--i)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
typedef double db;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int N=4e4+10;
struct node {
int v,x,id;
}a[N];
int n,m,tn,tb,tot;
int bel[N],cc[300][N],ansv[300][300],ansc[300][300];
int lb[300],rb[300];
void init() {
tn=(int)(pow(n/2.0,0.5)+0.5);
rep(i,1,n+1) {
bel[i]=(i-1)/tn+1,tb=bel[i];
lb[bel[i]]=lb[bel[i]]==0?i:lb[bel[i]];
rb[bel[i]]=i;
}
rep(i,1,tb+1) rep(j,lb[i],rb[i]+1) cc[i][a[j].x]++;
rep(i,1,tb+1) rep(j,1,tot+1) cc[i][j]+=cc[i-1][j];
rep(i,1,tb+1) {
static int cnt[N];
int mxc=0,mxv=0;
rep(j,i,tb+1) {
rep(k,lb[j],rb[j]+1) {
++cnt[a[k].x];
if(cnt[a[k].x]>mxc||(cnt[a[k].x]==mxc&&a[k].v<mxv))
mxv=a[k].v,mxc=cnt[a[k].x];
}
ansv[i][j]=mxv,ansc[i][j]=mxc;
}
rep(j,i,tb+1) rep(k,lb[j],rb[j]+1) --cnt[a[k].x];
}
}
#define getcc(l,r,k) (cc[r][k]-cc[l-1][k])
int query(int l,int r) {
static int cnt[N];
int bbl=bel[l],bbr=bel[r];
if(bbl==bbr) {
int ans1=0,ans2=0;
rep(i,l,r+1) {
++cnt[a[i].x];
if(cnt[a[i].x]>ans2||(cnt[a[i].x]==ans2&&a[i].v<ans1))
ans1=a[i].v,ans2=cnt[a[i].x];
}
rep(i,l,r+1) --cnt[a[i].x];
return ans1;
}
int l0=1,r0=0,l1=1,r1=0;
if(lb[bbl]!=l) l0=l,r0=rb[bbl],++bbl;
if(rb[bbr]!=r) l1=lb[bbr],r1=r,--bbr;
int ans1=ansv[bbl][bbr],ans2=ansc[bbl][bbr];
rep(i,l0,r0+1) {
++cnt[a[i].x];
int tmpc=cnt[a[i].x]+getcc(bbl,bbr,a[i].x);
if(tmpc>ans2||(tmpc==ans2&&a[i].v<ans1))
ans1=a[i].v,ans2=tmpc;
}
rep(i,l1,r1+1) {
++cnt[a[i].x];
int tmpc=cnt[a[i].x]+getcc(bbl,bbr,a[i].x);
if(tmpc>ans2||(tmpc==ans2&&a[i].v<ans1))
ans1=a[i].v,ans2=tmpc;
}
rep(i,l0,r0+1) --cnt[a[i].x];
rep(i,l1,r1+1) --cnt[a[i].x];
return ans1;
}
int main() {
#ifdef LOCAL
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
rep(i,1,n+1) {
scanf("%d",&a[i].v);
a[i].id=i;
}
sort(a+1,a+n+1,[](node a,node b) {
return a.v<b.v;
});
rep(i,1,n+1) a[i].x=a[i].v==a[i-1].v?a[i-1].x:++tot;
sort(a+1,a+n+1,[](node a,node b) {return a.id<b.id;});
init();
int lstans=0; while(m--) {
int l,r; scanf("%d%d",&l,&r);
l=(l+lstans-1)%n+1,r=(r+lstans-1)%n+1;
if(l>r) swap(l,r);
printf("%d\n",lstans=query(l,r));
}
return 0;
}
感觉跑的还挺快的qwq
来源:oschina
链接:https://my.oschina.net/u/4311641/blog/3300629