2020西工大校赛 G智乃与无意义的题目(线段树)
这题是单点修改和区间查询,因此想到用线段树求,问题是里面的因子个数的维护
显然不可能是先算出来再分解因子,因此我们想到唯一分解定理,也就是所有数都是某些质因数的倍数的乘积
并且每个数不超过10,10里面质数只有2 3 5 7 9,因此只需要维护这些值就行了,因此因数个数就是这个质因数的指数+1的乘积。
所以在修改的时候对每个数进行分解质因数,因为每个数只有10以内,所以不贡献复杂度
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; const int mod=998244353; int n,m; int a[N]; ll res[10]; struct node{ int l,r; int s[10]; }tr[N<<2]; void build(int u,int l,int r){ if(l==r){ tr[u]=node{l,l}; } else{ tr[u]=node{l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } } void pushup(int u){ int i; for(i=2;i<=9;i++){ tr[u].s[i]=tr[u<<1].s[i]+tr[u<<1|1].s[i]; } } void modify(int u,int l,int x){ if(tr[u].l==tr[u].r){ for(int i=2;i<=9;i++) tr[u].s[i]=0; int i; for(i=2;i*i<=x;i++){ if(x%i==0){ while(x%i==0){ tr[u].s[i]++; x/=i; } } } if(x>1) tr[u].s[x]++; return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,x); else modify(u<<1|1,l,x); pushup(u); } void query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r){ int i; for(i=2;i<=9;i++){ res[i]=(res[i]+tr[u].s[i])%mod; } return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) query(u<<1,l,r); if(r>mid) query(u<<1|1,l,r); } ll solve(int l,int r){ memset(res,0,sizeof res); int i; query(1,l,r); ll ans=1; for(i=2;i<=9;i++){ ans=(ans*(res[i]+1))%mod; } return ans; } int main(){ cin>>n>>m; int i; for(i=1;i<=n;i++){ scanf("%d",&a[i]); } build(1,1,n); for(i=1;i<=n;i++){ modify(1,i,a[i]); } int op; while(m--){ scanf("%d",&op); if(op==1){ int l,x; scanf("%d%d",&l,&x); modify(1,l,x); } else{ int l,r; scanf("%d%d",&l,&r); printf("%lld\n",solve(l,r)); } } }
没有人不辛苦,只有人不喊疼