CF1114F Please, another Queries on Array?

  • 考虑用线段树维护取模后的区间积和真正的区间积所含有的质因子.
  • 每次询问查得这两个值后,一乘一除,即可算出该区间积的欧拉函数.
  • 区间积容易维护,主要考虑如何维护所含的质因子.
  • 注意到 \(a_i\) 和每次乘的 \(x\) 都 \(\leq 300\) , 而 \(300\) 以内的质数恰有 \(62\) 个,所以可以用一个 \(62\) 位的非负整数状压表示一个区间所含的质因子,用 \(long\ long\) 恰能存下.
  • 注意用 \(long\ long\) 状压时需写成 \(1LL<<k\) .
  • 此题难点在于想到分别维护区间积和质因子,以及用状压记录质因子.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
int x=0;
bool pos=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
pos=0;
for(;isdigit(ch);ch=getchar())
x=x*10+ch-'0';
return pos?x:-x;
}
const int MAXN=4e5+10;
int prime[MAXN]={2,3,5,7,11,13,17,19,23,29,31,37,41,
43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,
127,131,137,139,149,151,157,163,167,173,179,181,191,193,
197,199,211,223,227,229,233,239,241,251,257,263,269,271,
277,281,283,293};
const int siz=62;
const int P=1e9+7;
int a[MAXN];
inline int add(int a,int b)
{
return (a + b) % P;
}
inline int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int inv(int x)
{
return fpow(x,P-2);
}
#define root Tree[o]
#define lson Tree[o<<1]
#define rson Tree[o<<1|1]
ll calcdiv(ll x)
{
ll res=0;
for(ll i=0;i<siz;++i)
if(x%prime[i]==0)
res|=(1LL<<i);
return res;
}
struct node{
int l,r;
ll div,prod;
int tag1;
ll tag2;
node()
{
div=0;
prod=1;
tag1=1;
tag2=0;
}
}Tree[MAXN<<2];
void pushup(int o)
{
root.prod=mul(lson.prod,rson.prod);
root.div=lson.div|rson.div;
}
void BuildTree(int o,int l,int r)
{
root.l=l,root.r=r;
if(l==r)
{
root.prod=a[l];
root.div=calcdiv(a[l]);
return;
}
int mid=(l+r)>>1;
BuildTree(o<<1,l,mid);
BuildTree(o<<1|1,mid+1,r);
pushup(o);
}
void Modifiy(int o,int v,ll div)
{
root.tag1=mul(root.tag1,v);
root.tag2|=div;
root.prod=mul(root.prod,fpow(v,root.r-root.l+1));
root.div|=div;
}
void pushdown(int o)
{
if(root.tag2==0)
return;
Modifiy(o<<1,root.tag1,root.tag2);
Modifiy(o<<1|1,root.tag1,root.tag2);
root.tag1=1;
root.tag2=0;
}
void update(int o,int L,int R,int v,ll div)
{
int l=root.l,r=root.r;
if(l>R || r<L)
return;
if(L<=l && r<=R)
{
Modifiy(o,v,div);
return;
}
int mid=(l+r)>>1;
pushdown(o);//修改时也要下传标记
if(L<=mid)
update(o<<1,L,R,v,div);
if(R>mid)
update(o<<1|1,L,R,v,div);
pushup(o);
}
int query(int o,int L,int R,ll &totdiv)
{
int l=root.l,r=root.r;
int res=1;
if(l>R || r<L)
return res;
if(L<=l && r<=R)
{
totdiv|=root.div;
return root.prod;
}
int mid=(l+r)>>1;
pushdown(o);
if(L<=mid)
res=mul(res,query(o<<1,L,R,totdiv));
if(R>mid)
res=mul(res,query(o<<1|1,L,R,totdiv));
return res;
}
int n,m;
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
n=read();
m=read();
for(int i=1;i<=n;++i)
a[i]=read();
BuildTree(1,1,n);
for(int p=1;p<=m;++p)
{
char buf[10];
scanf("%s",buf);
if(buf[0]=='M')
{
int l=read(),r=read(),x=read();
ll div=calcdiv(x);
update(1,l,r,x,div);
}
else
{
assert(buf[0]=='T');
int l=read(),r=read();
ll div=0;
int prod=query(1,l,r,div);
for(ll i=0;i<siz;++i)
{
if((div>>i)&1LL)
prod=mul(prod,prime[i]-1),prod=mul(prod,inv(prime[i]));
}
printf("%d\n",prod);
}
}
return 0;
}
05-23 21:31