CF920F SUM and REPLACE(线段树+思维)
这题比较套路,首先我们发现,区间变成约数个数是不可能用区间维护的,因此这题显然有个trick
既然只能暴力修改单点,但是我们又要要求修改次数不能太多,因此可以联想到,是不是我约数个数求几次就变成一个常数了
继续观察,果然是这样,因此我们发现修改次数不会太多
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=1e6+10; const int mod=1e9+7; int a[N]; struct node{ int l,r; int cnt; ll sum; }tr[N<<2]; bool mark[N]; int prim[N],d[N],num[N]; int cnt; void initial(){ cnt=0; d[1]=1; for (int i=2;i<N;++i){ if (!mark[i]){ prim[cnt++]=i; num[i]=1; d[i]=2; } for (int j=0;j<cnt&&i*prim[j]<N;++j){ mark[i*prim[j]]=1; if (!(i%prim[j])){ num[i*prim[j]]=num[i]+1; d[i*prim[j]]=d[i]/(num[i]+1)*(num[i*prim[j]]+1); break; } d[i*prim[j]]=d[i]*d[prim[j]]; num[i*prim[j]]=1; } } } void pushup(int u){ tr[u].cnt=tr[u<<1].cnt+tr[u<<1|1].cnt; tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void build(int u,int l,int r){ if(l==r){ tr[u]={l,r,a[l]==1,a[l]}; } else{ tr[u]={l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } void modify(int u,int l,int r){ ll x=tr[u].r-tr[u].l+1-tr[u].cnt; if(tr[u].sum-tr[u].cnt==x*2) return ; if(tr[u].l==tr[u].r){ tr[u].sum=d[tr[u].sum]; tr[u].cnt=(tr[u].sum==1)?1:0; return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r); if(r>mid) modify(u<<1|1,l,r); pushup(u); } ll query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r){ return tr[u].sum; } int mid=tr[u].l+tr[u].r>>1; ll ans=0; if(l<=mid) ans+=query(u<<1,l,r); if(r>mid) ans+=query(u<<1|1,l,r); return ans; } int main(){ ios::sync_with_stdio(false); int n,m; cin>>n>>m; int i; initial(); for(i=1;i<=n;i++){ cin>>a[i]; } build(1,1,n); while(m--){ int opt; cin>>opt; int l,r; cin>>l>>r; if(opt==1){ modify(1,l,r); } else{ cout<<query(1,l,r)<<endl; } } return 0; }
没有人不辛苦,只有人不喊疼