【BZOJ3813】奇数国 线段树+欧拉函数

【BZOJ3813】奇数国

Description

给定一个序列,每次改变一个位置的数,或是询问一段区间的数的乘积的phi值。每个数都可以表示成前60个质数的若干次方的乘积。

Sample Input

6
0 1 3
1 1 5
0 1 3
1 1 7
0 1 3
0 2 3

Sample Output

18
24
36
6

HINT

x≤100000,当ai=0时0≤ci−bi≤100000

题解:显然我们可以先求出区间乘积,然后判断一下每个质数是否在其中出现过即可,如果出现过,则ans*=(P-1)/P。

由于只有60个质数,所以用一个long long存起来就行,然后用线段树维护一下。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef long long ll;
const int maxn=100010;
int n=100000,m,num;
int pri[100],np[300];
ll ine[100];
const ll P=19961993;
struct node
{
	ll x,y;
	node() {}
	node(ll a,ll b)	{x=a,y=b;}
	node operator + (const node &a) const {return node(x*a.x%P,y|a.y);}
}s[maxn<<2];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
void build(int l,int r,int x)
{
	if(l==r)
	{
		s[x]=node(3,2);
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a,ll b)
{
	if(l==r)
	{
		s[x]=node(b,0);
		for(int i=1;i<=60;i++)	if(b%pri[i]==0)	s[x].y|=(1ll<<(i-1));
		return ;
	}
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b);
	else	updata(mid+1,r,rson,a,b);
	s[x]=s[lson]+s[rson];
}
node query(int l,int r,int x,int a,int b)
{
	if(a<=l&&r<=b)	return s[x];
	int mid=(l+r)>>1;
	if(b<=mid)	return query(l,mid,lson,a,b);
	if(a>mid)	return query(mid+1,r,rson,a,b);
	return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
inline ll pm(ll x,ll y)
{
	ll z=1;
	while(y)
	{
		if(y&1)	z=z*x%P;
		x=x*x%P,y>>=1;
	}
	return z;
}
int main()
{
	m=rd();
	int i,j,a,b,op;
	for(i=2;i<=281;i++)
	{
		if(!np[i])	pri[++num]=i,ine[num]=pm(i,P-2);
		for(j=1;j<=num&&i*pri[j]<=281;j++)
		{
			np[i*pri[j]]=1;
			if(i%pri[j]==0)	break;
		}
	}
	build(1,n,1);
	for(i=1;i<=m;i++)
	{
		op=rd(),a=rd(),b=rd();
		if(!op)
		{
			node tmp=query(1,n,1,a,b);
			for(j=1;j<=60;j++)	if((tmp.y>>(j-1))&1)	tmp.x=tmp.x*ine[j]%P*(pri[j]-1)%P;
			printf("%lld\n",tmp.x);
		}
		else	updata(1,n,1,a,b);
	}
	return 0;
}//6 0 1 3 1 1 5 0 1 3 1 1 7 0 1 3 0 2 3

 

posted @ 2017-10-15 10:57  CQzhangyu  阅读(298)  评论(0编辑  收藏  举报