关于玄学调块长,求助
查看原帖
关于玄学调块长,求助
107727
Acfun楼主2021/3/31 18:22

下面的代码是一份暴力分块,修改操作的时间复杂度约为 O(O(块数2) ^2)。经测试,块长为 n\sqrt{n} 会在 #10 TLE 0.17s;块长为 16201620 会在 #11 TLE,但 #11 不含修改操作,而其他数据点平均用时明显少于块长为 n\sqrt{n}

我在仔细浏览本题的讨论版时看见有大佬建议莫队的块长为 nt3+1\lceil\sqrt[3]{nt}\rceil+1,对于 #11 特判,但这样的块长用在下面的代码里只能得到 88pts。因此我想求助如下问题(可以与代码无关):

  • 在我的代码中,为什么块长为 16201620 可以在2s内通过所有数据?

  • 块长为 nt3+1\lceil\sqrt[3]{nt}\rceil+1 有何特殊优化?

  • 对于一些修改/查询操作次数不平均的题,该如何调块长?或如何求出类似于本题的 16201620 这种块长?

代码:

#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;
}
2021/3/31 18:22
加载中...