P14316

平衡!设 同阶。

尝试找到支配对,形如一些最小的 使得包含 的询问 可以存在。

对于右端点 ,考虑哪些 形成支配对。

,可以整除分块。对于 个区间 ,只考虑 最大的位置。

要维护值域上一个区间中最后一个出现的位置,即需要 单点修改 和 区间求 max。如果直接维护 ST 表,从下往上第 层要修改 个位置,一共 个位置。分块,块内块间分别建 ST 表,分别 修改,可以 查询。

对于 ,可以根号分治。若 ,可以直接枚举倍数 ,只考虑 最大的位置。否则 ,只考虑 的位置,其中 上一次出现的位置,对于每个值只用把整个序列扫一遍。

现在有 个支配对。从左往右扫右端点,维护 表示 出现的最小位置,加入在右端点的支配对 chkmx。用 单点加 和 后缀求和维护所有左端点的答案。

单用任意一个做法,可以正反各扫一遍,但是存支配对需要 空间。

精细实现整除分块,在 [ 分别枚举 ,可以使除法次数减半。

int n,m=400001,q,a[maxn];
vector<pii> ask[maxn];
int ans[maxn];
int lst[maxn],pos[maxn];
int addv[maxn],addb[maxm];
inline void upd(int p,int w){addv[p]+=w,addb[p/B]+=w;}
inline int que(int p){
	int id=p/B,ans=0;
	int pr=min(m,(id+1)*B);
	for(int i=p;i<pr;i++)ans+=addv[i];
	pr=m/B;
	for(int i=id+1;i<=pr;i++)ans+=addb[i];
	return ans;
}
inline void chk(int p,int w){
	if(lst[p]<w){
		upd(lst[p],-1),lst[p]=w,upd(lst[p],1);
	}
}
int stv[maxm][10][B+5],stb[10][maxm];
inline int quev(int id,int l,int r){
	int k=__lg(r-l+1);
	return max(stv[id][k][l],stv[id][k][r-(1<<k)+1]);
}
inline int queb(int l,int r){
	int k=__lg(r-l+1);
	return max(stb[k][l],stb[k][r-(1<<k)+1]);
}
inline int que(int l,int r){
	int idl=l/B,idr=r/B;
	if(idl==idr)return quev(idl,l-idl*B,r-idl*B);
	int res=0;
	res=max(res,quev(idl,l-idl*B,B-1));
	if(idl+1<=idr-1)res=max(res,queb(idl+1,idr-1));
	res=max(res,quev(idr,0,r-idr*B));
	return res;
}
void mdf(int p,int w){
	int id=p/B;p-=id*B;
	stv[id][0][p]=w;
	for(int i=1;i<10;i++){
		int pl=max(0,p-(1<<i)+1),pr=min(B-1-(1<<i)+1,p);
		for(int j=pl;j<=pr;j++)stv[id][i][j]=max(stv[id][i-1][j],stv[id][i-1][j+(1<<i-1)]);
	}
	stb[0][id]=quev(id,0,B-1);
	for(int i=1;i<10;i++){
		int pl=max(0,id-(1<<i)+1),pr=min(m/B-(1<<i)+1,id);
		for(int j=pl;j<=pr;j++)stb[i][j]=max(stb[i-1][j],stb[i-1][j+(1<<i-1)]);
	}
}
void work(){
	n=read();q=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=q;i++){
		int l=read(),r=read();
		ask[r].pb({l,i});
	}
	for(int i=1;i<=n;i++){
		mdf(a[i],i);
		for(int l=1;l*l<=a[i];l++){
			int x=a[i]/l;
			chk(x,pos[l]);
		}
		for(int x=1,r=a[i],l;x*x<=a[i];x++,r=l-1){
			l=a[i]/(x+1)+1;
			chk(x,que(l,r));
		}
		if(a[i]<=B){
			for(int j=pos[a[i]]+1;j<i;j++)chk(a[j]/a[i],j);
		}
		else{
			for(int k=0;k*a[i]<=m;k++)chk(k,que(k*a[i],min(m,(k+1)*a[i]-1)));
		}
		pos[a[i]]=i;
		chk(0,que(a[i]+1,m));
		for(auto[l,id]:ask[i])ans[id]=que(l);
	}
	for(int i=1;i<=q;i++)write(ans[i]),puts("");
}