给定一个数列,两种操作,
1 区间 乘 x
2 求区间 累乘 的欧拉函数 对 1e9+1 取模
我们发现线段树可以轻松搞定,可是 n 4e5 虽然 ai 只有 300,直接暴力肯定超 ll ,
首先区间 乘法 可以要线段树维护,而欧拉函数我们知道 = n* (p1-1)/p1 *(p2-1)/p2。。。
那么就可以逆元,而且 300以内素数有 62个,我们可以一一记录下来对于每个数,我们都先进行一次预处理,记录它的全部素因数,但是如果线段树每个点都开 62个 vis 会爆 memory ,因为只有 62个数,所以完全可以用一个 long long 状压掉,那么预处理就很简单了,之后只需要 区间维护的时候 其一是把数字相乘, 其二要把二者之间的状态进行一下 或 操作,所以不如用 pair
之后算出区间和之后,直接遍历这 62 个素数,出现过的就 代入一下欧拉公式。。。
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define ls rt<<1
#define rs rt<<1|1
#define root 1,1,n
#define pr pair<ll, ll>
#define mpr make_pair
#define fi first
#define se second
#define pb(a) push_back(a)
const int maxn=4e5+5;
const int mod=1e9+7;
inline ll lread()
{
register ll s=0,w=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
inline int read()
{
register int s=0,w=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
ll qpow(ll a,ll n)
{
ll num = 1;
while(n)
{
if(n&1) num=num*a%mod;
a = a*a%mod;
n >>= 1;
}
return num;
}
vector<ll>v;
ll mark[305];
pr mul(pr a, pr b){return mpr(a.fi*b.fi%mod, a.se|b.se);}
inline void init()
{
register bool vis[305];
register int cnt = 0;
memset(vis, false, sizeof vis);
memset(mark, 0, sizeof mark);
for(int i=2;i<=300;i++)
{
if(vis[i])continue;
v.pb(i);
for(int j=i;j<=300;j+=i)
{
vis[j]=true;
mark[j]|=1LL<<cnt;
}
cnt ++;
}
}
struct node
{
int l,r;
pr num; pr laz;
}a[maxn<<2];
inline void build(int rt,int l,int r)
{
a[rt].l=l, a[rt].r=r;
a[rt].laz={1,0};
if(l == r)
{
int x; scanf("%d",&x);
a[rt].num={x, mark[x]};
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
a[rt].num = mul(a[ls].num, a[rs].num);
}
inline void update(int rt,int x,int y,pr k)
{
if(x==a[rt].l && y==a[rt].r)
{
a[rt].laz = mul(a[rt].laz, k);
k.fi = qpow(k.fi, y-x+1);
a[rt].num = mul(a[rt].num, k);
return;
}
if(a[rt].laz.fi!=1 || a[rt].laz.se!=0)
{
update(ls, a[ls].l, a[ls].r, a[rt].laz);
update(rs, a[rs].l, a[rs].r, a[rt].laz);
a[rt].laz = {1,0};
}
if(y<=a[ls].r)update(ls, x, y, k);
else if(x>=a[rs].l)update(rs, x, y, k);
else
{
update(ls, x, a[ls].r, k);
update(rs, a[rs].l, y, k);
}
a[rt].num = mul(a[ls].num, a[rs].num);
}
pr query(int rt,int x,int y)
{
if(x==a[rt].l && y==a[rt].r) return a[rt].num;
if(a[rt].laz.fi!=1 || a[rt].laz.se!=0)
{
update(ls, a[ls].l, a[ls].r, a[rt].laz);
update(rs, a[rs].l, a[rs].r, a[rt].laz);
a[rt].laz = {1,0};
}
if(y<=a[ls].r)return query(ls, x, y);
else if(x>=a[rs].l)return query(rs, x, y);
return mul(query(ls, x, a[ls].r), query(rs, a[rs].l, y));
}
int main()
{
init();
ll n=lread(),q=lread();
build(1,1,n);
while(q --)
{
char str[10]; int L,R,x;
scanf("%s",str);
L=read(),R=read();
if(str[0]=='M')
{
x=read();
update(1, L, R, mpr(x, mark[x]));
}
else
{
pr num = query(1, L, R);
for(int i=0;i<62;i++)
{
if( (1LL<<i) & num.se )
{
num.fi = num.fi*qpow(v[i], mod-2)%mod;
num.fi = num.fi*(v[i]-1)%mod;
}
}
printf("%lld\n",num.fi);
}
}
return 0;
}