题目链接:点击查看
题意:长度100000的序列,原始都为3,两个操作,1 a b 把p[a] 改为b,0 a b 把[a,b] 区间数相乘,求这个数的欧拉值
题解:因为每个数都可以通过前60个素数表示,因为,所以我们维护下,区间的乘积,和区间的前60个素数有多少种,求的时候在用一下费马小定理即可,前60个素数的mod-2次方预处理一下,否则会超时
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=19961993;
struct node{
int l,r;
ll val;
ll laz;
bool sum[62];
}tree[N<<3];
int n;
ll a[N];
int prime[110],len,ok[510];
void pushup(int cur)
{
tree[cur].val=tree[cur<<1].val*tree[cur<<1|1].val%mod;
for(int i=1;i<=60;i++)
{
if(tree[cur<<1].sum[i] || tree[cur<<1|1].sum[i])
tree[cur].sum[i]=1;
else
tree[cur].sum[i]=0;
}
}
void build(int l,int r,int cur)
{
tree[cur].l=l;
tree[cur].r=r;
tree[cur].laz=1;
if(l==r)
{
tree[cur].val=3;
a[l]=3;
for(int i=1;i<=60;i++)
tree[cur].sum[i]=0;
tree[cur].sum[2]=1;
return;
}
int mid=(r+l)>>1;
build(l,mid,cur<<1);
build(mid+1,r,cur<<1|1);
pushup(cur);
}
bool ans[62];
ll query(int pl,int pr,int cur)
{
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
for(int i=1;i<=60;i++)
ans[i]|=tree[cur].sum[i];
return tree[cur].val;
}
ll su=1;
if(pl<=tree[cur<<1].r) su=query(pl,pr,cur<<1);
if(pr>=tree[cur<<1|1].l) su=(su*query(pl,pr,cur<<1|1))%mod;
return su;
}
void update(int pos,int cur,int val)
{
if(tree[cur].l==tree[cur].r)
{
tree[cur].val=(ll)val;
for(int i=1;i<=60;i++)
tree[cur].sum[i]=ans[i];
return;
}
if(pos<=tree[cur<<1].r) update(pos,cur<<1,val);
else update(pos,cur<<1|1,val);
pushup(cur);
}
ll ksm(ll b,ll k)
{
ll res=1;
while(k)
{
if(k&1) res=res*b%mod;
k>>=1;
b=b*b%mod;
}
return res;
}
ll pp[66];
int main()
{
int op,l,r;
for(int i=2;i<=600;i++)
{
if(ok[i]==0) prime[len++]=i;
if(len>=60) break;
for(int j=0;j<len&&prime[j]*i<=600;j++)
{
ok[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
// cout<<prime[59]<<endl;
ll m;
for(int i=0;i<60;i++)
pp[i]=ksm(prime[i],mod-2);
while(~scanf("%d",&n))
{
build(1,100000,1);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&op,&l,&r);
for(int j=1;j<=60;j++)
ans[j]=0;
if(op==0)
{
ll res=query(l,r,1);
// cout<<res<<endl;
for(int j=1;j<=60;j++)
if(ans[j])
res=res*(prime[j-1]-1)%mod*pp[j-1]%mod;
printf("%lld\n",res);
}
else
{
m=r;
for(int j=0;j<60;j++)
{
if(m%prime[j]==0)
{
ans[j+1]=1;
while(m%prime[j]==0)
m/=prime[j];
}
}
update(l,1,r);
}
}
}
return 0;
}