zoukankan      html  css  js  c++  java
  • 【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
    ",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
  • 相关阅读:
    主键索引就是聚集索引吗?
    聚集索引以及非聚集索引
    IO阻塞模型、IO非阻塞模型、多路复用IO模型
    Log4j的使用说明
    前置机是什么
    转:图文理解区块链
    DQL、DML、DDL、DCL全名是啥?
    OLAP和OLTP的区别
    JAVA之运算符优先级
    JAVA之异常处理(一)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7670232.html
Copyright © 2011-2022 走看看