题目链接: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;
}