下面的代码是一份暴力分块,修改操作的时间复杂度约为 O(块数2)。经测试,块长为 n 会在 #10 TLE 0.17s;块长为 1620 会在 #11 TLE,但 #11 不含修改操作,而其他数据点平均用时明显少于块长为 n。
我在仔细浏览本题的讨论版时看见有大佬建议莫队的块长为 ⌈3nt⌉+1,对于 #11 特判,但这样的块长用在下面的代码里只能得到 88pts。因此我想求助如下问题(可以与代码无关):
在我的代码中,为什么块长为 1620 可以在2s内通过所有数据?
块长为 ⌈3nt⌉+1 有何特殊优化?
对于一些修改/查询操作次数不平均的题,该如何调块长?或如何求出类似于本题的 1620 这种块长?
代码:
#include<cmath>
#include<cctype>
#include<cstdio>
#define ri register int
typedef long long ll;
const int maxn=27e4+10,maxp=375;
inline int qr(){
ri in=0;register char ch;
while(!isdigit(ch=getchar()));
do in=(in<<1)+(in<<3)+(ch^48);while(isdigit(ch=getchar()));
return in;
}
inline char gc(){
register char ch;
while(!isupper(ch=getchar()));
return ch;
}
template<class T>
void qw(T out){
if(out>9)qw(out/10);
putchar(out%10|48);
}
int a[maxn],b[1000010],bl,bel[maxn],cnt,kl[maxp],kr[maxp],m,n,num,q,sum[maxn][maxp],tot[maxp][maxp],vis[maxn];
// sum[i][j] 表示值为 i 的数在前 j 块中的出现次数, tot[i][j] 表示第 i 块到第 j 块中不同数的出现次数
struct node{
char op;
int l,r;
}qy[maxn];
inline void update(int pos,int v){ //修改操作
ri k=bel[pos];
for(ri i=1;i<=k;++i)
for(ri j=k;j<=cnt;++j){
if(sum[a[pos]][j]==sum[a[pos]][i-1]+1)--tot[i][j];
if(sum[v][j]==sum[v][i-1])++tot[i][j];
}
for(ri i=k;i<=cnt;++i)--sum[a[pos]][i],++sum[v][i];
a[pos]=v;
}
inline int query(int l,int r){ //查询操作
++num;
ri L=bel[l],R=bel[r],ret=0;
if(L==R){
for(ri i=l;i<=r;++i)
if(vis[a[i]]!=num)
vis[a[i]]=num,++ret;
return ret;
}
ret=tot[L+1][R-1];
for(ri i=l;i<=kr[L];++i)
if(vis[a[i]]!=num){
if(sum[a[i]][R-1]==sum[a[i]][L])++ret;
vis[a[i]]=num;
}
for(ri i=kl[R];i<=r;++i)
if(vis[a[i]]!=num){
if(sum[a[i]][R-1]==sum[a[i]][L])++ret;
vis[a[i]]=num;
}
return ret;
}
int main(){
n=qr(),q=qr();
for(ri i=1;i<=n;++i)b[a[i]=qr()]=true;
for(ri i=1;i<=q;++i){
qy[i].op=gc(),qy[i].l=qr(),qy[i].r=qr();
if(qy[i].op=='R')b[qy[i].r]=true,++m;
}
for(ri i=1;i<1000001;++i)
if(b[i])
b[i]=++bl; //离散化
if(1ll*m*m<=q)m=sqrt(n);
else m=1620;
for(ri i=1;i<=n;++i){
a[i]=b[a[i]];
if(i%m==1)kr[cnt]=i-1,kl[++cnt]=i;
bel[i]=cnt;
++sum[a[i]][bel[i]];
}
kr[cnt]=n;
for(ri i=1;i<=cnt;++i){
++num;
ri k=kl[i],s=0;
for(ri j=i;j<=cnt;++j){
for(;k<=kr[j];++k)
if(vis[a[k]]!=num)
++s,vis[a[k]]=num;
tot[i][j]=s;
}
for(ri j=1;j<=bl;++j)sum[j][i]+=sum[j][i-1];
}
for(ri i=1;i<=q;++i){
if(qy[i].op=='Q')qw(query(qy[i].l,qy[i].r)),putchar(10);
else{
qy[i].r=b[qy[i].r];
update(qy[i].l,qy[i].r);
}
}
fwrite(obuf,o-obuf,1,stdout);
return 0;
}