题目描述
对于正整数n,定义欧拉函数φ(n) 为小于等于n 且与n 互质的正整数个数。例如
φ(1) = 1,φ(8) = 4。
给定正整数序列a1; a2;…; an,请依次执行q 个操作,操作有以下三种类型:
• 0 i x:修改a[i] 的值为x;
• 1 l r:查询φ(a[l] + a[l+1] + … + a[r]) 的值,输出这个值对10^9 + 7 取模的结果;
• 2 l r:查询φ(a[l] * a[l+1] * … * a[r]) 的值,输出这个值对10^9 + 7 取模的结果。
解题思路
只考虑操作01,数据结构求和,暴力求phi即可。
单次最大复杂度
O(2e9√ln2e9√)
O
(
2
e
9
l
n
2
e
9
)
,2000左右,而且随机情况下复杂度肯定不满,开O2肯定能过。
不放心打millerrabin也可以…虽然最后复杂度估计400左右,不过常数也很大。
考虑操作2怎么做。
原式相当于
(∏iai)∗∏pp−1p
(
∏
i
a
i
)
∗
∏
p
p
−
1
p
,其中p枚举的是出现过的质因子。
前面部分用线段树顺便维护一下就行了,而后面部分则是经典的统计带权颜色数做法。
考虑我们需要统计带权等价类,即带权颜色数,我们考虑只统计每个颜色块的最左边被询问区间[l,r]包含的那个点,我们需要设计计算方法。
具体的,设这个点位置为y,他的前一个位置为x,我们考虑在怎样的[l,r]的区间内,他会被当成关键点。发现这样的区间满足
x<l<=y<=r
x
<
l
<=
y
<=
r
。那么转化成对于一个给定的区间[l,r],我们想统计所有满足这个条件的点对的贡献。发现可以变成二维区间查询问题,那么就是树套树或者KD树之类的维护一下区间乘积的经典操作了。
那么对于一个数,把每个质因子当成一种颜色,然后用set之类的维护每种颜色位置,每次修改就改一些点对即可,质因子的数量可以看成常数,那么时间复杂度是
O(nlog2n)
O
(
n
l
o
g
2
n
)
的·
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
const int N=1e5+5,M=5e6+5,mo=1e9+7;
multiset<int> col[N];
multiset<int> :: iterator it;
int pri[N],fac[N],rev[N],tr[2][N*4],n,m,i,a[N],l,ka,x,y,j,ref[N],ans,L,R,S,tmp,val,pos,d[N],z,v,ri,le;
int rt[N],vtr[M*3],ls[M*3],rs[M*3],ts;
bool pd[N];
int read()
{
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int ksm(int x,int y)
{
int ret=1;
while (y)
{
if (y&1) ret=1ll*ret*x%mo;
y>>=1;
x=1ll*x*x%mo;
}
return ret;
}
void Predo(int n)
{
int i,t,j;
fo(i,2,n)
{
if (!pd[i])
{
pri[++pri[0]]=i;
fac[i]=i;
if (i<=40000) ref[i]=pri[0];
}
fo(j,1,pri[0])
{
if (1ll*i*pri[j]>n) break;
t=i*pri[j];
pd[t]=1;
fac[t]=pri[j];
if (i%pri[j]==0)
break;
}
}
fo(i,1,40000) rev[i]=ksm(i,mo-2);
}
void change(int x,int l,int r)
{
if (l==r) {tr[0][x]=tr[1][x]=val;return;}
int m=l+r>>1;
if (pos<=m) change(x*2,l,m);
else change(x*2+1,m+1,r);
tr[0][x]=tr[0][x*2]+tr[0][x*2+1];
tr[1][x]=1ll*tr[1][x*2]*tr[1][x*2+1]%mo;
}
void calc(int x)
{
if (!S) ans+=x;
else ans=1ll*ans*x%mo;
}
void get(int x,int l,int r)
{
if (L<=l&&r<=R) {calc(tr[S][x]);return;}
int m=l+r>>1;
if (L<=m) get(x*2,l,m);
if (m<R) get(x*2+1,m+1,r);
}
int phi(int n)
{
int ret=1;
fo(i,1,pri[0])
{
if (pri[i]*pri[i]>n) break;
if (n%pri[i]==0)
{
n/=pri[i];
ret=ret*(pri[i]-1)%mo;
while (n%pri[i]==0)
{
n/=pri[i];
ret=ret*pri[i]%mo;
}
}
}
if (n>1) ret=ret*(n-1);
return ret%mo;
}
void get(int n)
{
int x;
d[0]=0;
while (n>1)
{
x=fac[n];
while (x==fac[n/x])
n/=x;
n/=x;
d[++d[0]]=x;
}
}
void ins(int &x,int l,int r,int p,int v)
{
if (!x) x=++ts,vtr[x]=1;
if (l==r) {vtr[x]=1ll*vtr[x]*v%mo;return ;}
int m=l+r>>1;
if (p<=m) ins(ls[x],l,m,p,v);
else ins(rs[x],m+1,r,p,v);
vtr[x]=1ll*vtr[ls[x]]*vtr[rs[x]]%mo;
}
void get(int x,int l,int r,int i,int j)
{
if (!x) return;
if (l==i&&r==j)
{tmp=1ll*tmp*vtr[x]%mo;return;}
int m=l+r>>1;
if (i<=m) get(ls[x],l,m,i,min(j,m));
if (m<j) get(rs[x],m+1,r,max(m+1,i),j);
}
void ins(int x,int y,int val)// constant added
{
x++;
while (x<n+1)
{
ins(rt[x],1,n,y,val);
x+=x&(-x);
}
}
void get(int lx,int rx,int ly,int ry)
{
int x;
x=rx+1;
while (x)
{
get(rt[x],1,n,ly,ry);
x-=x&(-x);
}
}
int main()
{
freopen("t2.in","r",stdin);
freopen("t2.out","w",stdout);
Predo(4e4);
scanf("%d %d",&n,&m);
fo(i,1,40000) col[i].insert(0);
vtr[0]=1;
fo(i,1,n)
{
a[i]=read();
pos=i;val=a[i];
change(1,1,n);
get(a[i]);
fo(j,1,d[0])
{
it=col[d[j]].end();
ins(*(--it),i,1ll*(d[j]-1)*rev[d[j]]%mo);
col[d[j]].insert(i);
}
}
fo(l,1,m)
{
ka=read();x=read();y=read();
if (!ka)
{
pos=x;val=y;
change(1,1,n);
get(a[x]);
fo(i,1,d[0])
{
z=d[i];
le=ri=0;
it=col[z].find(x);
col[z].erase(it);
it=col[z].lower_bound(x);
v=1ll*z*rev[z-1]%mo;
if (it!=col[z].end())
ins(x,ri=*it,v);
ins(le=*(--it),x,v);
if (ri) ins(le,ri,1ll*(z-1)*rev[z]%mo);
}
a[x]=y;
get(a[x]);
fo(i,1,d[0])
{
z=d[i];
le=ri=0;
it=col[z].lower_bound(x);
v=1ll*(z-1)*rev[z]%mo;
if (it!=col[z].end())
ins(x,ri=*it,v);
ins(le=*(--it),x,v);
if (ri) ins(le,ri,1ll*z*rev[z-1]%mo);
col[z].insert(x);
}
}
else if (ka==1)
{
L=x;R=y;ans=S=0;
get(1,1,n);
printf("%d\n",phi(ans));
}
else
{
L=x;R=y;tmp=ans=S=1;
get(1,1,n);
get(1,L-1,L,R);
ans=1ll*ans*tmp%mo;
printf("%d\n",ans);
}
}
ans=0;
}