线段数维护区间乘,欧拉函数和

The Euler function, φ, is known to be important in math theory. Given a positive integer n, φ(n) is defined as the number of integers in [1,n] that are co-prime with n. For example, φ(1)=1,φ(10)=4,φ(11)=10.

Now, given an array x with n positive integers x1,,xn, your task is to maintain m operations on x, which can be categorized into two types:

 

 

 

 

Input

The first line contains two inetegers n,(1n,m105).

The second line contains n integers x1,,xn (1xi100).

Then m lines follow. The i-th line describes the i-th operation. The input guarantees that 1lrn and 1w100.

Output

For each operation of type 1, output a single line with a single integer, representing the answer.

Sample Input

5 5
1 2 3 4 5
1 1 5
0 1 3 2
1 1 5
0 2 5 6
1 1 5
 
结尾无空行

Sample Output

10
11
37


这个题就是首先你要先知道欧拉函数的性质,ol[i]=n*(1-1/p1)*(1-1/p2)*(1-1/p3).......*(1-1/pn)
这个题就是用到这个性质,然后这a[i]和乘的每一个数都是<=100的质因子也就25个,可以用一个bitset来维护一下,

#include<iostream>
#include<algorithm>
#include<bitset>
using namespace std;
typedef long long ll;
const int maxn=5e5+100;
const ll mod = 998244353;
bitset<30>st[105];
struct node{
    bitset<30> st;
    ll x,lazy;
    int l,r;
}t[maxn];
int n,m;
int vis[maxn];
int idx;
int a[maxn],pri[100],cnt[105][30];
int f[maxn];//欧拉函数 
void inint(){
    for(int i=2;i<=100;i++){
        if(!vis[i]){
            pri[++idx]=i;
        }
        for(int j=1;j*pri[i]<maxn&&j<=idx;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                break;
            }
        }
    }
    for(int i=1;i<=100;i++){
        for(int j=1;j<=25;j++){
            int tmp=i;
            while(tmp%pri[j]==0){
                ++cnt[i][j];
                tmp/=pri[j];
            }
            st[i][j]=cnt[i][j];
        }
    }
}
int ol(int n){
    int ans=n;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            ans=ans/i*(i-1);
            while(n%i==0){
                n/=i;
            }
        }
    }
    if(n>1){
        ans=ans/n*(n-1);
    }
    return ans;
}
void push_up(int p){
    t[p].x=(t[2*p].x+t[2*p+1].x)%mod;
    t[p].st=(t[2*p].st & t[2*p+1].st);
}
void push_down(int p){
    t[2*p].lazy=(t[2*p].lazy*t[p].lazy)%mod;
    t[2*p+1].lazy=(t[2*p+1].lazy*t[p].lazy)%mod;
    t[2*p].x=(t[2*p].x*t[p].lazy)%mod;
    t[2*p+1].x=(t[2*p+1].x*t[p].lazy)%mod;
    t[p].lazy=1;     
}
void build(int p,int l,int r){
    t[p].l=l;
    t[p].r=r;
    t[p].lazy=1;
    if(t[p].l==t[p].r){
        t[p].x=1ll*f[a[l]];
        t[p].lazy=1;
        t[p].st=st[a[l]];
        return ;
    }
    int mid=(l+r)/2;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
    push_up(p);
}
void update(int p,int l,int r,int x,int y){
    if(t[p].l>=l&&t[p].r<=r&&t[p].st[x]){
        for(int i=1;i<=y;i++){
            t[p].x=(t[p].x*pri[x])%mod;
            t[p].lazy=(t[p].lazy*pri[x])%mod;
        }
        return ;
    }
    if(t[p].l==t[p].r){
        t[p].x=(t[p].x*(pri[x]-1))%mod;
        t[p].st[x]=1;
        for(int i=1;i<=y-1;i++){
            t[p].x=(t[p].x*pri[x])%mod;
        }
        return ;
    }
    if(t[p].lazy!=1){
        push_down(p);
    }
    int mid=(t[p].l+t[p].r)/2;
    if(l<=mid){
        update(2*p,l,r,x,y);
    }
    if(r>mid){
        update(2*p+1,l,r,x,y);
    }
    push_up(p);
} 
ll query(int p,int l,int r){
    if(t[p].l>=l&&t[p].r<=r){
        return t[p].x;
    }
    ll ans=0;
    if(t[p].lazy!=1){
        push_down(p);
    }
    int mid=(t[p].l+t[p].r)/2;
    if(l<=mid){
        ans+=query(2*p,l,r);
    }
    if(r>mid){
        ans+=query(2*p+1,l,r);
    }
    return ans;
}
//ll query(int p, int a, int b)
//{
//    if(a <= t[p].l && t[p].r <= b) return t[p].x;
//
//    if(t[p].lazy != 1) push_down(p);
//    int mid = (t[p].l + t[p].r) >> 1;
//    if(mid >= b) return query(p<<1, a, b);
//    else if(mid < a) return query(p<<1|1, a, b);
//    else return (query(p<<1, a, b) + query(p<<1|1, a, b)) % mod;
//}
int main(){
    inint();
    f[1]=1;
    for(int i=2;i<=100;i++){
        f[i]=ol(i);
    }
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    } 
    build(1,1,n);
    int op,a,b,c;
    while(m--){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d",&a,&b);
            printf("%lld\n",query(1,a,b)%mod);
        }
        else{
            scanf("%d%d%d",&a,&b,&c);
            for(int i=1;i<=25;i++){
                if(cnt[c][i]){
                    update(1,a,b,i,cnt[c][i]);
                }
            }
        }
    } 
}

 



posted @ 2021-09-28 00:59  lipu123  阅读(50)  评论(0)    收藏  举报