题解:P13984 数列分块入门 9
upd on 11/07:修改了代码里的小错误。感谢 @kohahahara。
大部分离线区间问题都可以使用莫队解决,这里说一个不用莫队且支持在线的做法。
做法
首先注意到一个性质:答案如果不是中间整块的众数,那答案一定在两边的散块中出现过。这个我认为比较显然。
首先离散化,这样值域就变成了
预处理
每次询问时,维护一个桶,把散块中的数依次添加,更新答案。但是这个桶我们显然不能每一次询问都全清一遍,这样复杂度就炸了。考虑到候选的答案只有
我们来求块长,预处理部分是
代码
注意要输出离散化前的原始值。
#include<bits/stdc++.h>
//#define int long long
#define R(x) x=read()
using namespace std;
inline int read() {
int x=0,y=1;
char e=getchar();
while(e<'0'||e>'9') {
if(e=='-')y=-1;
e=getchar();
}
while(e>='0'&&e<='9') {
x=(x<<1)+(x<<3)+(e^'0');
e=getchar();
}
return x*y;
}
const int N=300005,B=550;
int n,m,A[N],a[N],b[N];
int L[B],R[B],bel[N],cnt[B][N],res[B][B];
int t[N];
void build() {
int len=sqrt(n);
for(int i=1; i<=n; ++i) {
bel[i]=(i-1)/len+1;
if(bel[i]!=bel[i-1]) {
L[bel[i]]=i;
R[bel[i-1]]=i-1;
}
}
R[bel[n]]=n;
int tot=bel[n];
for(int i=1; i<=tot; ++i) {
for(int j=1; j<=n; ++j) {
cnt[i][j]=cnt[i-1][j];
}
for(int j=L[i]; j<=R[i]; ++j) {
++cnt[i][a[j]];
}
}
for(int i=1; i<=tot; ++i) {
memset(t,0,sizeof t);
int mx=0,who=1e9;
for(int j=i; j<=tot; ++j) {
for(int k=L[j]; k<=R[j]; ++k) {
++t[a[k]];
if(t[a[k]]>mx||(t[a[k]]==mx&&a[k]<who)) {
mx=t[a[k]];
who=a[k];
}
}
res[i][j]=who;
}
}
}
int ask(int l,int r) {
int p=bel[l],q=bel[r];
int mx,who;
if(p==q) {
mx=0,who=1e9;
for(int i=l; i<=r; ++i)t[a[i]]=0;
for(int i=l; i<=r; ++i) {
++t[a[i]];
if(t[a[i]]>mx||(t[a[i]]==mx&&a[i]<who)) {
mx=t[a[i]];
who=a[i];
}
}
} else {
//cnt[q-1]-cnt[p]
who=res[p+1][q-1];
mx=cnt[q-1][who]-cnt[p][who];
if(p+1>q-1)who=1e9;
for(int i=l; i<=R[p]; ++i) {
t[a[i]]=cnt[q-1][a[i]]-cnt[p][a[i]];
if(a[i]==who)++mx;
}
for(int i=L[q]; i<=r; ++i) {
t[a[i]]=cnt[q-1][a[i]]-cnt[p][a[i]];
if(a[i]==who)++mx;
}
for(int i=l; i<=R[p]; ++i) {
++t[a[i]];
if(t[a[i]]>mx||(t[a[i]]==mx&&a[i]<who)) {
mx=t[a[i]];
who=a[i];
}
}
for(int i=L[q]; i<=r; ++i) {
++t[a[i]];
if(t[a[i]]>mx||(t[a[i]]==mx&&a[i]<who)) {
mx=t[a[i]];
who=a[i];
}
}
}
return who;
}
signed main() {
R(n);
for(int i=1; i<=n; ++i) {
R(a[i]);
b[i]=a[i];
}
//a是离散化后的值
sort(b+1,b+1+n);
int tt=unique(b+1,b+1+n)-b-1;
for(int i=1; i<=n; ++i) {
int u=lower_bound(b+1,b+1+tt,a[i])-b;
A[u]=a[i];
a[i]=u;
}
//A是原始值
build();
int ans=0;
for(int i=1; i<=n; ++i) {
int R(l),R(r);
int u=ask(l,r);//rank
ans=A[u];
cout<<ans<<"\n";
}
return 0;
}