Codeforces 1732E - Location(狄利克雷前后缀和+分块)

一道挺有难度的 D2E,主要是因为太卡常了/tuu

好像想过很多别的做法,但因为都被卡常了所以就直接说过的做法了。

考虑分块,将操作分为修改和查询处理:

  • 修改:整块打 tag,边角块暴力改并重构得到这一块的最小值。

  • 查询:散块暴力处理,这部分都是套路。

    对于整块,如果没有 tag,那么直接用重构得到的最小值。

    如果有 tag,那么相当于求 \(\min\limits\dfrac{\text{lcm}(x,b_i)}{\gcd(x,b_i)}\)。首先 \(\dfrac{\text{lcm}(x,y)}{\gcd(x,y)}=\dfrac{xy}{\gcd(x,y)^2}\)。又考虑到是查询 \(\min\),而将分母往小里缩只会使得分数值变大,因此我们可以枚举 \(d\mid x\),然后查询这一块的 \(b_i\) 中是 \(d\) 的倍数且最小的那一个,然后答案对 \(\dfrac{b_ix}{d^2}\)\(\min\)。这样还是会超时,考虑使用狄利克雷前后缀和预处理一些东西,先一遍狄利克雷后缀和预处理出 \(d\) 的倍数中最小的 \(mn_d\),再一遍狄利克雷前缀和预处理出 \(mnn_x\) 表示 \(x\) 的因子 \(d\)\(\dfrac{mn_d}{d^2}\) 最小的。然后就可以 \(O(1)\) 查询这部分的值了。

时间复杂度 \(n\sqrt{n\log\log n}\)

const int BLK=300;
const int MAXN=5e4;
const ll INFll=0x3f3f3f3f3f3f3f3fll;
struct frac{
	ll a,b;
	frac(){a=1;b=0;}
	frac(ll _a,ll _b){a=_a;b=_b;}
	bool operator >(const frac &rhs){return 1ll*a*rhs.b>1ll*b*rhs.a;}
};
int pr[MAXN+5],prcnt=0,vis[MAXN+5];
void sieve(int n){
	for(int i=2;i<=n;i++){
		if(!vis[i])pr[++prcnt]=i;
		for(int j=1;j<=prcnt&&pr[j]*i<=n;j++)vis[pr[j]*i]=1;
	}
}
int n,qu,L[MAXN+5],R[MAXN+5],bel[MAXN+5],a[MAXN+5],b[MAXN+5],blk_sz,blk_cnt;
vector<int>fac[MAXN+5];int mn[BLK+5][MAXN+5];ll mnv[BLK+5];frac mnn[BLK+5][MAXN+5];
int tag[MAXN+5];
ll calc(int x,int y){int d=__gcd(x,y);return 1ll*x*y/d/d;}
void rebuild(int k){
	if(tag[k]){
		for(int i=L[k];i<=R[k];i++)a[i]=tag[k];
		tag[k]=0;
	}
}
ll calc_mn(int b,int v){return v/mnn[b][v].b*mnn[b][v].a;}
void modify(int l,int r,int v){
	if(bel[l]==bel[r]){
		rebuild(bel[l]);mnv[bel[l]]=INFll;
		for(int i=l;i<=r;i++)a[i]=v;
		for(int i=L[bel[l]];i<=R[bel[l]];i++)chkmin(mnv[bel[l]],calc(a[i],b[i]));
	}else{
		rebuild(bel[l]);mnv[bel[l]]=INFll;
		for(int i=l;i<=R[bel[l]];i++)a[i]=v;
		for(int i=L[bel[l]];i<=R[bel[l]];i++)chkmin(mnv[bel[l]],calc(a[i],b[i]));
		rebuild(bel[r]);mnv[bel[r]]=INFll;
		for(int i=L[bel[r]];i<=r;i++)a[i]=v;
		for(int i=L[bel[r]];i<=R[bel[r]];i++)chkmin(mnv[bel[r]],calc(a[i],b[i]));
		for(int i=bel[l]+1;i<bel[r];i++)tag[i]=v,mnv[i]=calc_mn(i,v);
	}
}
ll query(int l,int r){
	if(bel[l]==bel[r]){
		rebuild(bel[l]);ll mn=INFll;
		for(int i=l;i<=r;i++)chkmin(mn,calc(a[i],b[i]));
		return mn;
	}else{
		rebuild(bel[l]);rebuild(bel[r]);ll mn=INFll;
		for(int i=l;i<=R[bel[l]];i++)chkmin(mn,calc(a[i],b[i]));
		for(int i=L[bel[r]];i<=r;i++)chkmin(mn,calc(a[i],b[i]));
		for(int i=bel[l]+1;i<bel[r];i++)chkmin(mn,mnv[i]);
		return mn;
	}
}
int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	scanf("%d%d",&n,&qu);blk_sz=200;blk_cnt=(n-1)/blk_sz+1;
	sieve(MAXN);
	for(int i=1;i<=blk_cnt;i++){
		L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
		for(int j=L[i];j<=R[i];j++)bel[j]=i;
	}
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);
	for(int i=1;i<=MAXN;i++)for(int j=i;j<=MAXN;j+=i)fac[j].pb(i);
	memset(mn,63,sizeof(mn));memset(mnn,63,sizeof(mnn));memset(mnv,63,sizeof(mnv));
	for(int i=1;i<=blk_cnt;i++){
		for(int j=L[i];j<=R[i];j++)for(int p:fac[b[j]])chkmin(mn[i][p],b[j]/p);
		for(int j=1;j<=MAXN;j++)mnn[i][j]=frac(mn[i][j],j);
		for(int j=1;j<=prcnt;j++)for(int k=1;k*pr[j]<=MAXN;k++)chkmin(mnn[i][pr[j]*k],mnn[i][k]);
	}
	for(int i=1;i<=n;i++)chkmin(mnv[bel[i]],calc(a[i],b[i]));
	while(qu--){
		int opt;scanf("%d",&opt);
		if(opt==1){
			int l,r,v;scanf("%d%d%d",&l,&r,&v);
			modify(l,r,v);
		}else{
			int l,r;scanf("%d%d",&l,&r);
			printf("%lld\n",query(l,r));
		}
	}
	return 0;
}
posted @ 2022-12-22 16:47  tzc_wk  阅读(18)  评论(0编辑  收藏  举报