奇数国题解

原题
虽然 \(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\n",ans);
		}
	}
}
posted @ 2020-11-26 21:12  蒟蒻丁  阅读(97)  评论(0编辑  收藏  举报