• 【bzoj3813】奇数国 线段树


    题目描述

    给出一个长度为n的序列,每个数都可以由前60个质数的乘积表示,初始每个数都是3。支持两种操作:(1)修改一个数 (2)查询一段区间内所有数的乘积的欧拉函数值模19961993。

    输入

    第一行一个整数x表示领袖清点和变动存款的总次数。
    接下来x行,每行3个整数ai,bi,ci。ai为0时表示该条记录是清点计划,领袖会清点bi到ci的银行存款,你需要对该条记录计算出GFS想要的答案。ai为1时表示该条记录是存款变动,你要把银行bi的存款改为ci,不需要对该记录进行计算。

    输出

    输出若干行,每行一个数,表示那些年的答案。

    样例输入

    6
    013
    115
    013
    117
    013
    023

    样例输出

    18
    24
    36
    6


    题解

    线段树

    考虑到$varphi$的求法:$varphi(n)=nsumlimits_{prime(p)& p|n}frac{p-1}p$。所以需要维护的就是区间乘积和区间所有出现过的质数。

    由于所有数都可以由前60个质数表示,因此可以维护乘积中每个质数是否出现。使用二进制位运算即可。

    最后对于每个质因子计算并求出答案。

    时间复杂度$O(60m+mlog n)$。

    #include <cstdio>
    #define N 100010
    #define mod 19961993
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    typedef long long ll;
    const int n = 100000;
    int p[60] , inv[60];
    struct data
    {
    	ll w , v;
    	data() {}
    	data(int x)
    	{
    		int i;
    		w = x , v = 0;
    		for(i = 0 ; i < 60 ; i ++ )
    			if(x % p[i] == 0)
    				v |= (1ll << i);
    	}
    	data operator+(const data &a)const
    	{
    		data ans;
    		ans.w = w * a.w % mod , ans.v = v | a.v;
    		return ans;
    	}
    }a[N << 2];
    inline void pushup(int x)
    {
    	a[x] = a[x << 1] + a[x << 1 | 1];
    }
    void build(int l , int r , int x)
    {
    	if(l == r)
    	{
    		a[x] = data(3);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson) , build(rson);
    	pushup(x);
    }
    void update(int p , int v , int l , int r , int x)
    {
    	if(l == r)
    	{
    		a[x] = data(v);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(p <= mid) update(p , v , lson);
    	else update(p , v , rson);
    	pushup(x);
    }
    data query(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return a[x];
    	int mid = (l + r) >> 1;
    	if(e <= mid) return query(b , e , lson);
    	else if(b > mid) return query(b , e , rson);
    	else return query(b , e , lson) + query(b , e , rson);
    }
    inline ll pow(ll x , int y)
    {
    	ll ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x % mod;
    		x = x * x % mod , y >>= 1;
    	}
    	return ans;
    }
    inline bool judge(ll x)
    {
    	ll i;
    	for(i = 2 ; i * i <= x ; i ++ )
    		if(x % i == 0)
    			return 0;
    	return 1;
    }
    inline void init()
    {
    	ll i;
    	int tot = 0;
    	for(i = 2 ; tot < 60 ; i ++ )
    		if(judge(i))
    			p[tot] = i , inv[tot] = pow(p[tot] , mod - 2) , tot ++ ;
    
    }
    int main()
    {
    	init();
    	int m , i , x , y , z;
    	data t;
    	scanf("%d" , &m);
    	build(1 , n , 1);
    	while(m -- )
    	{
    		scanf("%d%d%d" , &x , &y , &z);
    		if(x) update(y , z , 1 , n , 1);
    		else
    		{
    			t = query(y , z , 1 , n , 1);
    			for(i = 0 ; i < 60 ; i ++ )
    				if(t.v & (1ll << i))
    					t.w = t.w * (p[i] - 1) % mod * inv[i] % mod;
    			printf("%lld
    " , t.w);
    		}
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    CDN实现原理
    openstack测试集群扩容配置
    ELK5.2.2自动化部署脚本
    Python多线程
    Python反射
    OpenStack快照分析:(三)从磁盘启动云主机离线(在线)快照分析
    OpenStack快照分析:(二)从镜像启动的云主机离在线快照分析
    OpenStack快照分析:(一)从镜像启动的云主机离线快照分析
    Python元编程
    Python源码阅读:对象
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7659498.html
Copyright © 2020-2023  润新知