尤拉函式 線段樹 狀壓 奇數國
阿新 • • 發佈:2018-11-08
讓我們一起來%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;
}