HYSBZ - 3813 奇数国 线段树区间维护+欧拉

题目链接:点击查看

题意:长度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;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/88616251