题目链接
题意:
求区间积的
ϕ
ϕ
值。
题解:
number∗x+product∗y=1
n
u
m
b
e
r
∗
x
+
p
r
o
d
u
c
t
∗
y
=
1
可以转化为
gcd(number,product)=1
g
c
d
(
n
u
m
b
e
r
,
p
r
o
d
u
c
t
)
=
1
,即求
ϕ(product)
ϕ
(
p
r
o
d
u
c
t
)
题目保证所有的数都可以表示成前60个质数的若干次方的形式,根据欧拉函数的性质,我们只需要维护区间的product和区间内出现了哪些质因数,product维护区间乘积很好做,但是维护60个质因数的话开60个变量可能可以,但是有可能被卡空间,这里其实可以用一个longlong来状压每个质数是否出现了。然后就是线段树了。
代码:
#include <bits/stdc++.h>
using namespace std;
int n;
long long mod=19961993,ni[70],p[70],cnt;
struct node
{
int l,r;
long long ji,p;
}tr[400010],ans;
inline void exgcd(long long a,long long b,long long &x,long long &y)
{
if(!b)
{
x=1;
y=0;
return;
}
else
{
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
inline void pushup(int rt)
{
tr[rt].ji=tr[rt<<1].ji*tr[rt<<1|1].ji%mod;
tr[rt].p=tr[rt<<1].p|tr[rt<<1|1].p;
}
inline void build(int rt,int l,int r)
{
tr[rt].l=l;
tr[rt].r=r;
if(l==r)
{
tr[rt].ji=3;
tr[rt].p=2;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
inline void update(int rt,int x,int y)
{
int l=tr[rt].l,r=tr[rt].r;
if(l==r)
{
long long cur=0;
for(long long i=1;i<=60;++i)
{
if(y%p[i]==0)
cur|=(1LL<<(i-1));
}
tr[rt].p=cur;
tr[rt].ji=y;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
update(rt<<1,x,y);
else
update(rt<<1|1,x,y);
pushup(rt);
}
inline void query(int rt,int le,int ri)
{
int l=tr[rt].l,r=tr[rt].r;
if(le<=l&&r<=ri)
{
ans.ji=(ans.ji*tr[rt].ji)%mod;
ans.p|=tr[rt].p;
return;
}
int mid=(l+r)>>1;
if(le<=mid)
query(rt<<1,le,ri);
if(ri>=mid+1)
query(rt<<1|1,le,ri);
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=300;++i)
{
int pd=0;
for(int j=2;j<=sqrt(i);++j)
{
if(i%j==0)
{
pd=1;
break;
}
}
if(pd==0)
{
p[++cnt]=i;
if(cnt==60)
break;
}
}
for(int i=1;i<=cnt;++i)
{
long long x,y;
x=0;
y=0;
exgcd(p[i],mod,x,y);
x=(x%mod+mod)%mod;
if(!x)
x+=mod;
ni[i]=x;
}
build(1,1,100000);
for(int i=1;i<=n;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==0)
{
ans.p=0;
ans.ji=1;
query(1,y,z);
long long res=ans.ji;
for(long long j=1;j<=60;++j)
{
if(ans.p&(1LL<<(j-1)))
res=(res*(p[j]-1)%mod*ni[j])%mod;
}
printf("%lld\n",res);
}
else
update(1,y,z);
}
return 0;
}