Codeforces1114 F. Please, another Queries on Array?(线段树+状压+欧拉函数)

题意:

给定长度为n的序列a,q次操作,操作有两种:
1.将[L,R]所有数乘上x
2.查询[L,R]区间乘积的欧拉函数值

答案对1e9+7取模

数据范围:n<=4e5,q<=2e5,1<=a(i),x<=300

解法:

欧拉函数拆分:
在这里插入图片描述

这道题选用最后一个式子,因为最后一个式子中的(p-1)/p可以预处理,那么只需要维护区间乘积n就行了

维护乘积显然线段树
打表观察到300以内只有62个质数,再状压一个二进制数,维护区间内出现过哪些质数即可

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//
const int maxm=4e5+5;
const int mod=1e9+7;
//
int ppow(int a,int b,int mod){
    int ans=1%mod;a%=mod;
    while(b){
        if(b&1)ans=1LL*ans*a%mod;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return ans;
}
//
int p[105],cnt;
int inv[105];
bool isprime(int x){
    for(int i=2;i*i<=x;i++){
        if(x%i==0)return 0;
    }
    return 1;
}
void init(){
    for(int i=2;i<=300;i++){
        if(isprime(i)){
            inv[cnt]=1LL*(i-1)*ppow(i,mod-2,mod)%mod;
            p[cnt++]=i;
        }
    }
}
//
int a[maxm<<2];
int laz[maxm<<2];
ll flaz[maxm<<2];
ll flag[maxm<<2];
void pushup(int node){
    flag[node]=(flag[node*2]|flag[node*2+1]);
    a[node]=1LL*a[node*2]*a[node*2+1]%mod;
}
void pushdown(int node,int l,int r){
    if(laz[node]!=1){
        int mid=(l+r)/2;
        a[node*2]=1LL*a[node*2]*ppow(laz[node],mid-l+1,mod)%mod;
        a[node*2+1]=1LL*a[node*2+1]*ppow(laz[node],r-mid,mod)%mod;
        laz[node*2]=1LL*laz[node*2]*laz[node]%mod;
        laz[node*2+1]=1LL*laz[node*2+1]*laz[node]%mod;
        laz[node]=1;
    }
    if(flaz[node]){
        flag[node*2]|=flaz[node];
        flag[node*2+1]|=flaz[node];
        flaz[node*2]|=flaz[node];
        flaz[node*2+1]|=flaz[node];
        flaz[node]=0;
    }
}
void build(int l,int r,int node){
    laz[node]=1;
    if(l==r){
        scanf("%d",&a[node]);
        flag[node]=0;
        for(int i=0;i<62;i++){
            if(a[node]%p[i]==0){
                flag[node]|=(1LL<<i);
            }
        }
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,node*2);
    build(mid+1,r,node*2+1);
    pushup(node);
}
void update(int st,int ed,int val,int l,int r,int node){
    if(st<=l&&ed>=r){
        a[node]=1LL*a[node]*ppow(val,r-l+1,mod)%mod;
        laz[node]=1LL*laz[node]*val%mod;
        for(int i=0;i<62;i++){
            if(val%p[i]==0){
                flag[node]|=(1LL<<i);
                flaz[node]|=(1LL<<i);
            }
        }
        return ;
    }
    pushdown(node,l,r);
    int mid=(l+r)/2;
    if(st<=mid)update(st,ed,val,l,mid,node*2);
    if(ed>mid)update(st,ed,val,mid+1,r,node*2+1);
    pushup(node);
}
pair<int,ll> ask(int st,int ed,int l,int r,int node){
    if(st<=l&&ed>=r){
        return {a[node],flag[node]};
    }
    pushdown(node,l,r);
    int mid=(l+r)/2;
    pair<int,ll>ans={1,0},temp;
    if(st<=mid){
        temp=ask(st,ed,l,mid,node*2);
        ans.first=1LL*ans.first*temp.first%mod;
        ans.second|=temp.second;
    }
    if(ed>mid){
        temp=ask(st,ed,mid+1,r,node*2+1);
        ans.first=1LL*ans.first*temp.first%mod;
        ans.second|=temp.second;
    }
    return ans;
}
//
char s[100];
int n,q;
signed main(){
    init();
    //
    scanf("%d%d",&n,&q);
    build(1,n,1);
    while(q--){
        scanf("%s",s);
        if(s[0]=='M'){
            int l,r,x;scanf("%d%d%d",&l,&r,&x);
            update(l,r,x,1,n,1);
        }else if(s[0]=='T'){
            int l,r;scanf("%d%d",&l,&r);
            pair<int,ll>ans=ask(l,r,1,n,1);
            int res=ans.first;
            for(int i=0;i<62;i++){
                if(ans.second>>i&1){
                    res=1LL*res*inv[i]%mod;
                }
            }
            printf("%d\n",res);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107374459