#include <bits/stdc++.h>
#define gc IO::fastgc()
#define pc(c) IO::fastpc(c)
#define int long long
using namespace std;
namespace IO{
char ibuf[1<<23],obuf[1<<23],*ip1=ibuf,*ip2=ibuf,*o=obuf;
inline char fastgc(){
return ((ip1==ip2)&&(ip2=(ip1=ibuf)+fread(ibuf,1,1<<21,stdin),ip1==ip2)?EOF:*ip1++);
}
inline void fastpc(char c){
*(o++)=c;
}
inline int read(){
register int t=0,f=1;
register char c=gc;
while(c!='-'&&(c<'0'||c>'9')) c=gc;
if(c=='-') c=gc,f=-1;
while(c>='0'&&c<='9') t=10*t+(c^48),c=gc;
return f*t;
}
inline char readc(){
register char c=gc;
while(c==' '||c=='\t'||c=='\r'||c=='\n'||c==0||c==EOF) c=gc;
return c;
}
inline void write(int x){
if(!x) return (void)pc('0');
if(x<0) pc('-'),x=-x;
static char c[33]={""};
static int cc=0;
while(x) c[++cc]=x%10,x/=10;
while(cc) pc(c[cc--]|48);
}
inline void flush(){
fwrite(obuf,o-obuf,1,stdout);
}
struct IO_Flusher{
inline IO_Flusher(){}
inline ~IO_Flusher(){
flush();
}
}__io_flusher_;
}
using IO::read;
using IO::readc;
using IO::write;
constexpr int N=400007,NN=1600007,A=307,PC=77;
constexpr int P=1000000007;
typedef bitset<PC> fset;
int n,q,a[N];
struct Node{
int l,r,v,lzv;
fset f,lz;
}tr[NN];
int d[A],pcnt,inv[A];
vector<int> prime;
fset fac[A];
inline void sieve(int n){
d[1]=1;
for(int i=2;i<=n;++i){
if(!d[i]){
d[i]=i;
prime.push_back(i);
}
for(auto j:prime){
int t=i*j;
if(t>n||j>d[i]) break;
d[t]=j;
}
}
}
inline void getinv(int n){
inv[1]=1;
for(int i=2;i<=n;++i){
inv[i]=((-(P/i)*inv[P%i])%P+P)%P;
}
}
inline int dquery(int _){
return lower_bound(prime.begin(),prime.end(),_)-prime.begin();
}
inline void buildf(fset &f,int x){
// printf("bf %d:",x);
for(int i=2;i*i<=x;++i){
if(!(x%i)){
// printf("%d ",i);
f[dquery(i)]=1;
while(!(x%i)){
x/=i;
}
}
}
if(x>1){
// printf("%d",x);
f[dquery(x)]=1;
}
// printf("\n");
}
inline void init(int n){
sieve(n);
getinv(n);
pcnt=prime.size();
for(int i=1;i<=n;++i){
buildf(fac[i],i);
// outfset(fac[i]),pc('\n');
}
// for(int i=1;i<=n;++i){
// printf("inv[%lld]=%lld\n",i,inv[i]);
// }
}
inline void mul(int k,int x,const fset &fx){
tr[k].v=(tr[k].v*x)%P;
tr[k].lzv=(tr[k].lzv*x)%P;
tr[k].f|=fx;
tr[k].lz|=fx;
}
inline void pushup(int k){
tr[k].v=tr[k<<1].v*tr[k<<1|1].v%P;
tr[k].f=tr[k<<1].f|tr[k<<1|1].f;
}
inline void pushdown(int k){
if(tr[k].lzv!=1){
mul(k<<1,tr[k].lzv,tr[k].lz);
mul(k<<1|1,tr[k].lzv,tr[k].lz);
tr[k].lzv=1;
tr[k].lz.reset();
}
}
void build(int k,int l,int r){
tr[k].l=l,tr[k].r=r,tr[k].lz.reset(),tr[k].lzv=1;
if(l==r){
tr[k].v=a[l];
tr[k].f=fac[a[l]];
return;
}
int m=(l+r)>>1;
build(k<<1,l,m);
build(k<<1|1,m+1,r);
pushup(k);
}
void modify(int k,int l,int r,int x){
if(tr[k].l>r||tr[k].r<l) return;
if(tr[k].l>=l&&tr[k].r<=r) return mul(k,x,fac[x]);
pushdown(k);
modify(k<<1,l,r,x);
modify(k<<1|1,l,r,x);
pushup(k);
}
fset query(int k,int l,int r){
if(tr[k].l>r||tr[k].r<l) return fac[0];
if(tr[k].l>=l&&tr[k].r<=r) return tr[k].f;
fset a;a.reset();
pushdown(k);
a|=query(k<<1,l,r);
a|=query(k<<1|1,l,r);
return a;
}
int queryv(int k,int l,int r){
if(tr[k].l>r||tr[k].r<l) return 1;
if(tr[k].l>=l&&tr[k].r<=r) return tr[k].v;
int a=1;
pushdown(k);
a=a*queryv(k<<1,l,r)%P;
a=a*queryv(k<<1|1,l,r)%P;
return a;
}
inline void outfset(const fset &x){
for(int i=0;i<pcnt;++i){
if(x[i]){
printf("%lld(%lld) ",i,prime[i]);
}
}
}
signed main(){
int l,r,x;
fset t;
init(300);
n=read(),q=read();
for(register int i=1;i<=n;++i){
a[i]=read();
}
build(1,1,n);
while(q--){
switch(readc()){
case 'M':{
l=read(),r=read(),x=read();
modify(1,l,r,x);
break;
}
case 'T':{
l=read(),r=read();
t=query(1,l,r);
x=queryv(1,l,r);
// printf("t=");outfset(t);printf("\n");
// printf("x=%lld\n",x);
for(register int i=0;i<pcnt;++i){
if(t[i]){
x=x*(prime[i]-1)%P;
x=x*inv[prime[i]]%P;
}
}
write(x),pc('\n');
break;
}
}
}
return 0;
}
思路就是用线段树维护区间乘积、区间中出现的质因数,然后暴力算欧拉函数。
但是,WA on #3。
有没有大佬能看看有什么问题,或者给个规模较小的 hack?