原题
虽然 (ntf) 学长嘲讽了这道题,但我认为这道题很适合我(菜鸡)了解线段树的有趣用法
首先翻译题面,就是每次进行一个操作——询问一个区间内所有数的乘积的欧拉函数或者修改数列中的一个数
由于每个数上限是(10^6),暴力求完一个区间的乘积再套欧拉函数是不可能的
首先了解先欧拉函数的公式
[φ(x)=x*prod_{i|x且i为质数}^{}{(1-frac{1}{i})}
]
看到这个公式,发现我们其实没有必要求出区间数的乘积,我们只需要知道这个乘积里会有几个不同的质数就可以了
然后每个数不超过(10^6),所以会出现的质数不超过(60)个,可以状态压缩
用一个(f)数组记录取模后的区间乘积,用一个(ff)记录区间内出现的质数种类的状压,每次查询一个区间的这两个值就能求出这个区间乘积的欧拉函数
下面说下具体过程,不想剧透的小伙伴可以开始敲代码了
- 1、对于每个修改操作,分解出这个数的每个质因数,并状压
- 2、对于查询,首先求出区间积(公式里的x)
- 3、查询这个区间质因数种类的状压数字,还原出有哪些质因数
- 4、用第二步和第三步求出的值直接求欧拉函数
时间复杂度为(O(60*n*log(len)))
下面AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define mid ((l+r)/2)
#define ll long long
using namespace std;
const ll P[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281};
const ll inv[]={9980997,6653998,11977196,8555140,5444180,1535538,10568114,14708837,3471651,11701858,17386252,1618540,16066970,2321162,18263100,16948862,12518538,15380552,10725847,1686929,13399146,17182475,12025297,15924736,13582387,395287,6395590,15857658,16299242,6359573,3300802,18742940,6702567,10914471,16210746,11765678,5340151,18247466,7769638,8077107,11932588,6506948,1985748,6619521,5877135,4413707,9744480,10115270,14597757,16475182,18334191,5011379,18885205,7555336,621385,11309266,12170137,12006660,18304499,11153142};
const ll mod=19961993;
ll n,f[8000010],ff[8000010];
void build(ll l,ll r,ll o){
if(l==r){
f[o]=2,ff[o]=3;
return ;
}
build(l,mid,o*2);
build(mid+1,r,o*2+1);
f[o]=f[o*2]|f[o*2+1];
ff[o]=ff[o*2]*ff[o*2+1]%mod;
}
void modify(ll l,ll r,ll o,ll x,ll d,ll d2){
if(l==r){
f[o]=d,ff[o]=d2;
return ;
}
if(x<=mid)modify(l,mid,o*2,x,d,d2);
else modify(mid+1,r,o*2+1,x,d,d2);
f[o]=f[o*2]|f[o*2+1];
ff[o]=ff[o*2]*ff[o*2+1]%mod;
}
ll Query(ll l,ll r,ll o,ll i,ll j){
if(i<=l&&r<=j){
return ff[o];
}
ll ret=1;
if(i<=mid)ret=ret*Query(l,mid,o*2,i,j)%mod;
if(mid<j)ret=ret*Query(mid+1,r,o*2+1,i,j)%mod;
return ret;
}
ll query(ll l,ll r,ll o,ll i,ll j){
if(i<=l&&r<=j){
return f[o];
}
ll ret=0;
if(i<=mid)ret|=query(l,mid,o*2,i,j);
if(mid<j)ret|=query(mid+1,r,o*2+1,i,j);
return ret;
}
ll pre_work(ll x){
ll tmp=0;
for(ll i=0;i<60;i++){
if(x%P[i]==0)tmp|=(1ll<<i);
}
return tmp;
}
int main(){
cin>>n;
for(ll i=1;i<=100000;i++)modify(1,100000,1,i,2,3);
while(n--){
ll opt,a1,a2;
scanf("%lld%lld%lld",&opt,&a1,&a2);
if(opt==1)modify(1,100000,1,a1,pre_work(a2),a2);
else {
ll tmp=query(1,100000,1,a1,a2);
ll ans=Query(1,100000,1,a1,a2);
for(ll i=0,a1;i<60;i++){
if(tmp&(1ll<<i)){
ans=(ans*inv[i])%mod,ans=(ans*(P[i]-1))%mod;
}
}
printf("%lld
",ans);
}
}
}