让我们一起来%forever_shi神犇
题意:求区间积的 值。
题解:
可以转化为
,即求
。
题目保证所有的数都可以表示成前60个质数的若干次方的形式,根据欧拉函数的性质,我们只需要维护区间的product和区间内出现了哪些质因数,product维护区间乘积很好做,但是维护60个质因数的话开60个变量可能可以,但是有可能被卡空间,这里其实可以用一个ll来状压每个质数是否出现了。然后就是线段树了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=19961993;
int m,num;
ll p[1000];
ll inv[1000];
struct node
{
int l,r;
ll mul,p;
}tr[1001000],ans;
ll ksm(ll q,ll w)
{
ll h=1;
while(w)
{
if(w&1)
h=h*q%mod;
q=q*q%mod;
w>>=1;
}
return h;
}
void pushdown(int rt)
{
tr[rt].mul=(tr[rt*2].mul%mod*tr[rt*2+1].mul%mod)%mod;
tr[rt].p=tr[rt*2].p|tr[rt*2+1].p;
}
void build(int rt,int l,int r)
{
tr[rt].l=l;
tr[rt].r=r;
if(l==r)
{
tr[rt].mul=3;
tr[rt].p=2;
return;
}
int mid=(l+r)/2;
build(rt*2,l,mid);
build(rt*2+1,mid+1,r);
pushdown(rt);
}
void update(int rt,int x,int y)
{
int l=tr[rt].l;
int r=tr[rt].r;
if(l==r)
{
ll now=0;
for(ll i=1;i<=60;++i)
if(y%p[i]==0)
now+=(1LL<<(i-1));
tr[rt].p=now;
tr[rt].mul=y;
return;
}
int mid=(l+r)/2;
if(x<=mid)
update(rt*2,x,y);
else
update(rt*2+1,x,y);
pushdown(rt);
}
void query(int rt,int L,int R)
{
int l=tr[rt].l;
int r=tr[rt].r;
if(l>=L&&r<=R)
{
ans.mul=(ans.mul%mod*tr[rt].mul%mod)%mod;
ans.p|=tr[rt].p;
return;
}
int mid=(l+r)/2;
if(L<=mid)
query(rt*2,L,R);
if(R>=mid+1)
query(rt*2+1,L,R);
}
int main()
{
scanf("%d",&m);
for(int i=2;i<=300;++i)
{
int sum=0;
for(int j=1;j<=i;++j)
if(i%j==0)
sum++;
if(sum<=2)
p[++num]=i;
if(num==60)
break;
}
for(int i=1;i<=60;++i)
inv[i]=ksm(p[i],mod-2);
build(1,1,100000);
for(int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==0)
{
ans.mul=1;
ans.p=0;
query(1,y,z);
ll res=ans.mul;
for(int j=1;j<=60;++j)
if(ans.p&(1LL<<(j-1)))
res=(res%mod*(p[j]-1)%mod*inv[j]%mod)%mod;
printf("%lld\n",res);
}
else
update(1,y,z);
}
return 0;
}