主要解法
肯定要提前预留出di 数组,然后就是线段树。
刚开始以为 因子数=i-phi[i]+1
后来发现并不是,4和6不是因子关系,但是他们不是互质的,这两个的含义不一样, 并不是互补的
我们发现数据范围为1e6,然后一步步迭代 最终都会变成 1或者 2 d[1]=1 d[2]=2; 最多可迭代6次。
刚开始按照线段树一般解法,用Update 区间修改,是这点的话,就变成d[i],不是的话,就往下放,并且要push-up
查询用long long
后来发现超时了,我们发现不是每次都需要往下放的,就比如 d[2]=d[d[2]],就没有任何意义。
我们用一个最大值来定义区间的最大值,如果最大值<=2,那么就不必往下放,节约时间。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 #include <cctype> 10 #include <sstream> 11 using namespace std; 12 typedef long long ll; 13 const int inf=0x7fffffff; 14 const int N=1e6+100; 15 const int M=3*1e5+100; 16 ll tree[M<<2],d[N],mx[M<<2]; 17 int n,m; 18 void init() 19 { 20 for(int i=1;i<N;i++) 21 for(int j=i;j<N;j+=i) 22 d[j]++; 23 //for(int i=1;i<=10;i++) 24 // cout<<i<<" "<<d[i]<<endl; 25 } 26 void push_up(int rt) 27 { 28 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; 29 mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 30 } 31 void build(int rt,int l,int r) 32 { 33 if(l==r) 34 { 35 scanf("%lld",&tree[rt]); 36 mx[rt]=tree[rt]; 37 return; 38 } 39 int m=(l+r)/2; 40 build(rt<<1,l,m); 41 build(rt<<1|1,m+1,r); 42 push_up(rt); 43 } 44 void update(int L,int R,int rt,int l,int r) 45 { 46 if(mx[rt]<=2) return ; 47 if(l==r) 48 { 49 tree[rt]=mx[rt]=d[tree[rt]]; 50 return ; 51 } 52 int m=(l+r)/2; 53 if(L<=m) update(L,R,rt<<1,l,m); 54 if(R>m) update(L,R,rt<<1|1,m+1,r); 55 push_up(rt); 56 } 57 ll query(int L,int R,int rt,int l,int r) 58 { 59 if(L<=l&&r<=R) return tree[rt]; 60 ll ans=0; 61 int m=(l+r)/2; 62 if(L<=m) ans+=query(L,R,rt<<1,l,m); 63 if(R>m) ans+=query(L,R,rt<<1|1,m+1,r); 64 return ans; 65 } 66 int main() 67 { 68 init(); 69 scanf("%d %d",&n,&m); 70 build(1,1,n); 71 while(m--) 72 { 73 int k,l,r; 74 scanf("%d %d %d",&k,&l,&r); 75 if(k==1) 76 update(l,r,1,1,n); 77 else 78 cout<<query(l,r,1,1,n)<<endl; 79 } 80 81 return 0; 82 }
解决这种题目的方法:
1.提前写出d[i]数组
2.线段树
3.看是否可以优化。