这个题原来是黑题的说
来写点清(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 imes 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
",lstans=query(l,r));
}
return 0;
}
感觉跑的还挺快的qwq