思路:线段树区间乘法,维护$\phi(x_i)$,每次update w的质因子。

几个性质:

  1. 当$m$与$n$互质时有$\phi(m*n)==\phi(m)*\phi(n)$(这时使用单点修改)
  2. 当$k$是一个质数时,$\phi(k)==k-1$(这个代码里没有用到,但可以便于打表)
  3. $w$是一个质数,此时如果$\gcd(w,x_i)==w$则$\phi(w*x_i)==w*\phi(x_i)$。(如果一个区间里的$x_i$都满足这一点,可以区间修改)
2021ICPC预选赛第二场——L Euler Function_#include2021ICPC预选赛第二场——L Euler Function_#include_02
  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 #include<cstdlib>
  7 using namespace std;
  8 
  9 #define mxp 114 //最大需要处理的数字
 10 #define ll long long
 11 #define rep(i,l,r) for(int i=l;i<=r;++i)
 12 #define drep(i,r,l) for(int i=r;i>=l;--i)
 13 #define maxn 114514
 14 #define lson rt<<1
 15 #define rson rt<<1|1
 16 inline char nc(){
 17     static char buf[100010],*p1=buf,*p2=buf;
 18     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
 19 }
 20 #ifndef ONLINE_JUDGE
 21 #define nc() getchar()
 22 #endif
 23 inline int read(){
 24     int x=0,y=1;
 25     char ch=nc();
 26     while(ch<'0'||ch>'9'){
 27         if(ch=='-')y=-y;
 28         ch=nc();
 29     }
 30     while(ch>='0'&&ch<='9'){
 31         x=10*x+(ch^48);
 32         ch=nc();
 33     }
 34     return x*y;
 35 }
 36 int n,m,cnt;
 37 ll phi[255];
 38 const ll mod=998244353;
 39 ll tr_phi[maxn<<2];//欧拉函数之和
 40 ll seq[maxn];
 41 ll tag_mul[maxn<<2];
 42 bool isNP[514];
 43 ll prime[514];
 44 bool MUL[maxn<<2][514];
 45 inline void getprime(int x){
 46     rep(i,2,x){
 47         if(!isNP[i])prime[++cnt]=i;
 48         rep(j,1,cnt){
 49             if(i*prime[j]>x)break;
 50             isNP[i*prime[j]]=1;
 51             if(i%prime[j]==0)break;
 52         }
 53     }
 54 }
 55 void pushdown(int l,int r,int rt){
 56     int mid=(l+r)>>1;
 57     if(tag_mul[rt]!=1){
 58         tr_phi[lson]*=tag_mul[rt];
 59         tr_phi[lson]%=mod;
 60         tr_phi[rson]*=tag_mul[rt];
 61         tr_phi[rson]%=mod;
 62         tag_mul[lson]*=tag_mul[rt];
 63         tag_mul[lson]%=mod;
 64         tag_mul[rson]*=tag_mul[rt];
 65         tag_mul[rson]%=mod;
 66         tag_mul[rt]=1;
 67     }
 68     return;
 69 }
 70 void pushup(int rt){
 71     tr_phi[rt]=(tr_phi[lson]%mod+tr_phi[rson]%mod)%mod;
 72     rep(i,2,mxp){
 73         MUL[rt][i]=MUL[lson][i]&MUL[rson][i];
 74     }
 75 }
 76 void build(int l,int r,int rt){
 77     tag_mul[rt]=1;
 78     if(l==r){
 79         int dt=seq[l];
 80         tr_phi[rt]=phi[dt];
 81         rep(i,1,cnt){
 82             int cur_pm=prime[i];
 83             if(dt%cur_pm==0){
 84                 MUL[rt][cur_pm]=1;
 85             }
 86         }
 87         return;
 88     }
 89     int mid=(l+r)>>1;
 90     build(l,mid,lson);
 91     build(mid+1,r,rson);
 92     pushup(rt);
 93 }
 94 void update(int L,int R,int l,int r,int rt,ll w){//这个更新的w只考虑质因子。
 95     if(L<=l&&R>=r&&MUL[rt][w]){   
 96         tr_phi[rt]*=w;
 97         tag_mul[rt]*=w;
 98         tr_phi[rt]%=mod;
 99         tag_mul[rt]%=mod;
100         return;
101     }
102     if(l==r){
103         tr_phi[rt]*=phi[w];
104         tr_phi[rt]%=mod;
105         tag_mul[rt]=1;
106         MUL[rt][w]=1;
107         return;
108     }
109     pushdown(l,r,rt);
110     int mid=(l+r)>>1;
111     if(L<=mid)update(L,R,l,mid,lson,w);
112     if(mid+1<=R)update(L,R,mid+1,r,rson,w);
113     pushup(rt);
114 }
115 ll query(int L,int R,int l,int r,int rt){
116     if(r<L||l>R)return 0;
117     if(L<=l&&r<=R)return tr_phi[rt];
118     pushdown(l,r,rt);
119     int mid=(l+r)>>1;
120     return (query(L,R,l,mid,lson)%mod+query(L,R,mid+1,r,rson)%mod)%mod;
121 }
122 inline void getphi(int x){
123     phi[0]=0,phi[1]=1;
124     rep(i,2,x)phi[i]=i;
125     rep(i,2,x){
126         if(phi[i]==i){
127             for(int j=i;j<=x;j+=i){
128                 phi[j]=phi[j]/i*(i-1);
129             }
130         }
131     }
132 }
133 int main(){
134     getphi(125);
135     getprime(125);
136     n=read(),m=read();
137     rep(i,1,n){
138         seq[i]=read();
139     }
140     build(1,n,1);bool flag=1;
141     rep(i,1,m){
142         int op=read(),x=read(),y=read();
143         
144         if(op==1){
145             flag? printf("%lld",query(x,y,1,n,1)),flag=0:printf("\n%lld",query(x,y,1,n,1));
146         }
147         else if(op==0){
148             ll up=read();
149             int cur=1;
150             while(cur<=cnt){
151                 ll cur_p=prime[cur];
152                 while(up%cur_p==0){
153                     update(x,y,1,n,1,cur_p);
154                     up/=cur_p;    
155                 }
156                 if(up==1)break;
157                 ++cur;
158             }
159         }
160     }
161     return 0;
162 }
View Code