题目大意:
一个数列 支持两种操作
1 把区间内的数变成他们自己的约数个数
2 求区间和
思路:
可以想到每个数最终都会变成2或1
然后我们可以线段树
修改的时候记录一下每段有没有全被修改成1或2 是的话就不修改了
不是就暴力修改 因为每个数被修改的次数很小
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 1001000 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 18 return x*f; 19 } 20 int n,g[MAXN],cnt[MAXN],m; 21 struct data{ll sum,mx;}tr[MAXN<<2]; 22 inline void pshp(int k) 23 { 24 tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum; 25 tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx); 26 } 27 void build(int k,int l,int r) 28 { 29 if(l==r) {tr[k].sum=tr[k].mx=g[l];return ;} 30 int mid=(l+r)>>1; 31 build(k<<1,l,mid);build(k<<1|1,mid+1,r); 32 pshp(k); 33 } 34 inline ll query(int k,int a,int b,int l,int r) 35 { 36 if(l==a&&r==b) return tr[k].sum; 37 int mid=(l+r)>>1; 38 if(mid>=b) return query(k<<1,a,b,l,mid); 39 else if(mid<a) return query(k<<1|1,a,b,mid+1,r); 40 else return query(k<<1,a,mid,l,mid)+query(k<<1|1,mid+1,b,mid+1,r); 41 } 42 inline void upd(int k,int a,int b,int l,int r) 43 { 44 if(tr[k].mx<=2) return ; 45 if(l==r) {tr[k].sum=tr[k].mx=cnt[tr[k].mx];return ;} 46 int mid=(l+r)>>1; 47 if(mid>=b) upd(k<<1,a,b,l,mid); 48 else if(mid<a) upd(k<<1|1,a,b,mid+1,r); 49 else {upd(k<<1,a,mid,l,mid);upd(k<<1|1,mid+1,b,mid+1,r);} 50 pshp(k); 51 } 52 int main() 53 { 54 int a,b,c; 55 for(int i=1;i<=MAXN;i++) 56 for(int j=i;j<=MAXN;j+=i) cnt[j]++; 57 n=read(),m=read(); 58 for(int i=1;i<=n;i++) g[i]=read(); 59 build(1,1,n); 60 while(m--) 61 { 62 a=read(),b=read(),c=read(); 63 if(a==1) upd(1,b,c,1,n); 64 else printf("%I64d\n",query(1,b,c,1,n)); 65 } 66 }