F. Please, another Queries on Array?

https://codeforces.com/contest/1114/problem/F

操作二,维护区间乘积的值的欧拉值\varphi(\prod ai) 

\varphi (x)=x*(\prod (p-1)/p)  

p是\prod ai的质因数

操作一,懒标记乘300以内的数,维护ai也是300以内的数

因此我们只要维护300以内的质数的状态就可以了

用埃氏筛来筛出300以内的质数

因此我们维护300以内的质数的状态,以及区间乘积,懒标记(乘法标记,标记值x的质因数有哪些)

维护操作就是区间或,区间乘

思路很明了,操作有点复杂

而且需要优化

我们考虑优化质数状态,通过筛法得知300以内有62个质数,可以状态压缩到一个long long 数的二进制位上,如果超过ll,可以开bitset空间优化成 (n/32)

在计算的结果的时候要求逆元,对与mod数较大(mod>1e7) O(logb)的,我们可以线性求逆元

实际上更大的优化是线段树不要用结构体,写几个数组就可以了,但是个人不是很好看

code

// Problem: F. Please, another Queries on Array?
// Contest: Codeforces - Codeforces Round 538 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1114/F
// Memory Limit: 256 MB
// Time Limit: 5500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<bitset>
using namespace std;
typedef long long ll;
typedef long long LL;
const int N=4e5+9;
const int mod=1e9+7;
const int ZS=65;//300内质数数量62,开大点防止越界
const int p[65]={0,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,283,293};
int pp[500];//映射
int inv[500],f[65];
//modint
int ADD(int a, int b){return (a + b) % mod;}
int MUL(int a, int b){return 1ll * a * b % mod;}
int SUB(int a, int b){return ((a - b) % mod + mod) % mod;}
//
int a[N];
ll qmi(ll a,ll b){
	ll res=1;
	while(b){
		if(b&1){
			res=res*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
//处理质数 300 打表
bitset<500> prime;
void init(){	
	// prime[1]=1;
	// for(int i=2;i<=300/i;i++){
		// if(!prime[i]){
			// for(int j=2*i;j<=300;j+=i){
				// prime[j]=1;
			// }
		// }
	// }
	// for(int i=1;i<=300;i++){
		// if(!prime[i]){
			// cout<<i<<',';
		// }
	// }
	// cout<<'\n';
	//映射index
	for(int i=1;i<=62;i++){
		pp[p[i]]=i;
	}
	//线性处理逆元O(n)
	inv[1]=1;
	for(int i=2;i<=301;i++){
		inv[i]=MUL(inv[mod%i],(mod-mod/i));	
	}
	for(int i=1;i<=62;i++){
		f[i]=MUL((p[i]-1),inv[p[i]]);
	}
}
//线段树
struct SEG{
    #define INF (1ll<<63)
    #define ll long long
    #define tl(id) (id<<1)
    #define tr(id) (id<<1|1)
    #define li inline
    struct Info{//信息
    	ll num;//状态压缩,状态量超过63可以用bitset
    	int cfval;//乘积
        li Info friend operator + (const Info &a,const Info &b){//合并改
            Info res;
            res.num=a.num|b.num;
            res.cfval=MUL(a.cfval,b.cfval);
            return res;
        }
    };
    struct Tag{//标记
    	ll tag;
    	ll mul;//乘法标记
        Tag(){init();}
        li void init(){//初始化改
        	mul=1;
        	tag=0;
        	//都是0
        }
        li Tag friend operator + (const Tag &a,const Tag &b){//增加质因数
            Tag t;
            t.tag=a.tag|b.tag;
           	t.mul=MUL(a.mul,b.mul);
            return t;
        }
    };
    struct node{
        int l,r;
        Info val;
        Tag lazy;
    }seg[N<<2];
    #define pushup(id) seg[id].val=seg[tl(id)].val+seg[tr(id)].val;
    li int inrange(int L,int R,int l,int r){return l<=L && R<=r;}
    li int outofrange(int L,int R,int l,int r){return L>r || R<l;}
    li void build(const int id,int l,int r){
        seg[id].l=l,seg[id].r=r;
        seg[id].lazy.init();//初始化
        if(l==r){
            //质因数分解
            seg[id].val.cfval=a[l];
            if(a[l]==1){
            	return;
            }
            int x=a[l];
            for(int i=2;i<=x/i;i++){
				if(x%i==0){
					while(x%i==0){
						x/=i;
					}
					seg[id].val.num|=(1ll<<pp[i]);
				}
			}
			if(x>1){
				seg[id].val.num|=(1ll<<pp[x]);
			}
            return;
        }
        int mid=(l+r)>>1;
        build(tl(id),l,mid);
        build(tr(id),mid+1,r);
        pushup(id);
    }
    li void maketag(int id,int l,int r,Tag v){
    	seg[id].val.num|=v.tag;
    	seg[id].val.cfval=MUL(seg[id].val.cfval,qmi(v.mul,r-l+1));//维护区间乘积
    	seg[id].lazy=seg[id].lazy+v;
    }
     li void pushdown(int id,int l,int r){
        int mid=(l+r)>>1;
        maketag(tl(id),l,mid,seg[id].lazy);
        maketag(tr(id),mid+1,r,seg[id].lazy);
        seg[id].lazy.init();//初始化
     }
    li Info query(int id,int l,int r){
        if(inrange(seg[id].l,seg[id].r,l,r)){
            return seg[id].val;
        }else{
            int mid=(seg[id].l+seg[id].r)>>1;
            pushdown(id,seg[id].l,seg[id].r);
            if(mid>=r){
                return query(tl(id),l,r);
            }else if(mid<l){
                return query(tr(id),l,r);
            }else{
                return (query(tl(id),l,mid)+query(tr(id),mid+1,r));
            }
        }
    }
    li void modify(int id,int L,int R,int l,int r,Tag x){
        if(inrange(L,R,l,r)){
            maketag(id,L,R,x);
        }else if(!outofrange(L,R,l,r)){
            int mid=(L+R)>>1;
            pushdown(id,L,R);
            modify(tl(id),L,mid,l,r,x);
            modify(tr(id),mid+1,R,l,r,x);
            pushup(id);
        }
    }
}t;
SEG::Tag v;
//处理修改的x
void pre(int x){
	v.mul=x;
	v.tag=0;
	for(int i=2;i<=x/i;i++){
		if(x%i==0){
			while(x%i==0){
				x/=i;
			}
			v.tag|=(1ll<<pp[i]);
		}
	}
	if(x>1){
		v.tag|=(1ll<<pp[x]);
	}
}
#define Tag SEG::Tag
#define Info SEG::Info
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	init();
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	t.build(1,1,n);
	for(int i=1;i<=q;i++){
		string op;
		cin>>op;
		if(op[0]=='M'){
			int l,r,x;
			cin>>l>>r>>x;
			pre(x);
			t.modify(1,1,n,l,r,v);
		}else{
			int l,r;
			cin>>l>>r;
			Info res=t.query(1,l,r);
			ll ans=res.cfval;
			for(int i=1;i<=62;i++){
				if(res.num&(1ll<<i)){
					ans=MUL(ans,f[i]);
				}
			}
			cout<<(ans%mod+mod)%mod<<'\n';
		}
		// for(int i=1;i<=n;i++){
			// Info ans=t.query(1,i,i);
			// cout<<"cfval"<<" "<<ans.cfval<<'\n';
			// cout<<i<<" "<<"质因数"<<'\n';
			// for(int i=1;i<=62;i++){
				// if(ans.num&(1ll<<i)){
					// cout<<p[i]<<" ";
				// }
			// }
			// cout<<'\n';
		// }
		// cout<<'\n';
		// cout<<'\n';
		// cout<<'\n';
		// cout<<'\n';
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值