“美登杯”上海市高校大学生程序设计邀请赛 (华东理工大学) E 小花梨的数组 线段树

题意

分析

预处理出每个数的最小素因子,首先可以知道\(minprime(x*minprime(x))=minprime(x)\),我们用线段树维护区间最大值\(mx[p]\),注意这里的最大值并不是实际的最大值,同时维护区间\(a[i]\)\(minprime(a[i])\)的次数的最小值\(mnt[p]\)

  • 对于操作1,直接区间更新\(mnt[p]\)加1。

  • 对于操作2,有两种情况:

    • \(mnt[p]=0\)时,表示当前区间内至少有一个数乘最小素因子的次数为0,一个数除以它的最小素因子后它的最小素因子可能会变化,当一个数为1时,无论怎么操作它都不会再变了,而一个数除它的最小素因子最多\(log\)次就会变成1,所以此时我们直接暴力更新\(mx[p]=mx[p]/minprime(mx[p])\);

    • \(mnt[p]\not= 0时\),直接区间更新\(mnt[p]\)减1。

  • 对于操作3,单点查询\(mx[p]\)\(mnt[p]\),答案为\(mx[p]\times minprime(mx[p])^{mnt[p]}\),用快速幂算一下就行了。

为什么维护区间最大值\(mx[p]\)呢,因为当\(mx[p]=1\)时可以直接剪枝。

时间复杂度\(O(n*log(max(a[i]))*log(n))\)

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=1e5+10;
typedef pair<int,int> pii;
int n,m;
int a[maxn];
int mp[10*maxn];
int mx[maxn<<2],mnt[maxn<<2],tag[maxn<<2];
void pp(int p){
	mx[p]=max(mx[p<<1],mx[p<<1|1]);
	mnt[p]=min(mnt[p<<1],mnt[p<<1|1]);
}
void pd(int p,int k){
	mnt[p]+=k;
	tag[p]+=k;
}
void bd(int l,int r,int p){
	if(l==r){
		mx[p]=a[l];
		return;
	}int mid=l+r>>1;
	bd(lson);bd(rson);pp(p);
}
void up(int dl,int dr,int l,int r,int p,int k){
	if(mx[p]==1) return;
	if(l>=dl&&r<=dr){
		if(mnt[p]==0&&k==-1){
			if(l==r){
				mx[p]/=mp[mx[p]];
				return;
			}
		}else{
			mnt[p]+=k;
			tag[p]+=k;
			return;
		}
	}int mid=l+r>>1;
	pd(p<<1,tag[p]);pd(p<<1|1,tag[p]);tag[p]=0;
	if(dl<=mid) up(dl,dr,lson,k);
	if(dr>mid) up(dl,dr,rson,k);
	pp(p);
}
pii qy(int x,int l,int r,int p){
	if(l==r){
		return pii(mx[p],mnt[p]);
	}int mid=l+r>>1;
	pd(p<<1,tag[p]);pd(p<<1|1,tag[p]);tag[p]=0;
	if(x<=mid) return qy(x,lson);
	else return qy(x,rson);
}
int getmp(int x){
	for(int i=2;i*i<=x;i++){
		if(x%i==0) return i;
	}
	return x;
}
ll ksm(ll a,ll b){
	ll ret=1;
	while(b){
		if(b&1) ret=ret*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ret;
}
int main(){
	//ios::sync_with_stdio(false);
	//freopen("in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}mp[1]=1;
	for(int i=2;i<=1000000;i++){
		mp[i]=getmp(i);
	}bd(1,n,1);
	while(m--){
		int op,l,r,x;
		scanf("%d",&op);
		if(op==1){
			scanf("%d%d",&l,&r);
			up(l,r,1,n,1,1);
		}else if(op==2){
			scanf("%d%d",&l,&r);
			up(l,r,1,n,1,-1);
		}else{
			scanf("%d",&x);
			pii ret=qy(x,1,n,1);
			ll ans=1ll*ret.fi*ksm(mp[ret.fi],ret.se)%mod;
			printf("%lld\n",ans);
		}
	}
	return 0;
}
posted @ 2019-09-05 15:02  xyq0220  阅读(206)  评论(0编辑  收藏  举报