"美登杯"上海邀请赛 E.小花梨的数组(线段树)

题目链接:https://acm.ecnu.edu.cn/contest/173/problem/E/

题解:可以用线段树维护一个Add和Del 代表这个区间执行了几次增加和删除 增加操作直接区间Add++即可 但是Del操作就要思考一下了,考虑最终的状态 对于一个数 一定是删除了一定的最小质因子 然后对于目前的最小质因子增加一定的次数 若先增加再减少 那么便相当于没有变化,所以当这个区间存在Add,便直接在Add删去当前想要删除的次数,若没有则直接增加Del,开始可以用单调队列预处理每一个数的所有质因子

#include
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 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;j1) 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=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;
}

 

你可能感兴趣的:(数论,思维,数据结构,线段树)