"美登杯"上海邀請賽 E.小花梨的數組(線段樹)

題目鏈接:https://acm.ecnu.edu.cn/contest/173/problem/E/

題解:可以用線段樹維護一個Add和Del 代表這個區間執行了幾次增加和刪除 增加操作直接區間Add++即可 但是Del操作就要思考一下了,考慮最終的狀態 對於一個數 一定是刪除了一定的最小質因子 然後對於目前的最小質因子增加一定的次數 若先增加再減少 那麼便相當於沒有變化,所以當這個區間存在Add,便直接在Add刪去當前想要刪除的次數,若沒有則直接增加Del,開始可以用單調隊列預處理每一個數的所有質因子

#include<bits/stdc++.h>
using namespace std;
#define Sheryang main
const int maxn=2e5+7;
typedef long long ll;
const int mod=1e9+7;
//#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
#define IO cin.tie(0),ios::sync_with_stdio(false);
#define pi acos(-1)
#define PII pair<ll,ll>
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
/** keep hungry and keep calm! **/

ll a[maxn],Add[maxn<<2],Del[maxn<<2];
int n;

void pushdown(int rt){
	if(Add[rt]==0 && Del[rt]==0){
		return;
	}
	
	ll t = min(Del[rt],Add[rt<<1]);
	Add[rt<<1] -= t;
	Del[rt<<1] += Del[rt] - t;
	Add[rt<<1] += Add[rt];
	
	t = min(Del[rt],Add[rt<<1|1]);
	Add[rt<<1|1] -= t;
	Del[rt<<1|1] += Del[rt] - t;
	Add[rt<<1|1] += Add[rt];
	
	Add[rt] = Del[rt] = 0;
}

void update(int l,int r,int ty,int L=1,int R=n,int rt=1){
	if(L>=l && R<=r){
		if(ty==1){
			Add[rt] ++;
		}else{
			if(Add[rt]>0){
				Add[rt] --;
			}else{
				Del[rt] ++;
			}
		}
		return;
	}
	pushdown(rt);
	int mid = L+R>>1;
	if(l<=mid){
		update(l,r,ty,L,mid,rt<<1);
	}
	if(r>mid){
		update(l,r,ty,mid+1,R,rt<<1|1);
	}
}

ll query(int x,int ty,int l=1,int r=n,int rt=1){
	if(l==r){
		if(ty==1){
			return Add[rt];
		}else{
			ll ans = Del[rt];
			Del[rt] = 0;
			return ans;
		}
	}
	pushdown(rt);
	int mid = l+r>>1;
	if(x<=mid){
		return query(x,ty,l,mid,rt<<1);
	}else{
		return query(x,ty,mid+1,r,rt<<1|1);
	}
}

int head[maxn],tail[maxn],que[maxn][40];
int prime[maxn],vis[(int)1e6+7],cot;
void primeall(){
	
	for(int i=2;i<=1e6;i++){
		if(!vis[i]){
			prime[cot++] = i;
		}
		for(int j=0;j<cot&&prime[j]*i<=1e6;j++){
			vis[prime[j]*i] = 1;
			if(i%prime[j]==0){
				break;
			}
		}
	}
}
ll qpow(ll a,ll b){
	ll ans = 1;
	while(b){
		if(b&1){
			ans = ans*a%mod;
		}
		a = a*a%mod;b/=2;
	}
	return ans;
}

int Sheryang(){
    
    primeall();
   	n = read;
	int Q = read;
   	
   	for(int i=1;i<=n;i++){
   		a[i] = read;
   		head[i] = 1;
   		ll t = a[i];
   		for(int j=0;prime[j]*prime[j]<=t;j++){
			while(t%prime[j]==0){
				que[i][++tail[i]] = prime[j];
				t /= prime[j];
			}
		}
		if(t>1) que[i][++tail[i]] = t;
	}
	
	while(Q--){
		int op = read;
		if(op==3){
			
			int x = read;
			ll A = query(x,1),b = query(x,2);
			
			for(int i=0;i<b&&tail[x]>=head[x];i++){
				a[x] /= que[x][head[x]++];
			}
			ll pri = 1;
			if(head[x]<=tail[x]){
				pri = que[x][head[x]];
			}
			printf("%lld\n",qpow(pri,A)*a[x]%mod);
			
		}else{
			int l=read,r=read;
			update(l,r,op);
		}
	}
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章