cf920F SUM and REPLACE 树状数组+set 维护
题目:
Let D(x) be the number of positive divisors of a positive integer x. For example, D(2) = 2 (2 is divisible by 1 and 2), D(6) = 4 (6 is divisible by 1, 2, 3 and 6).
You are given an array a of n integers. You have to process two types of queries:
- REPLACE l r — for every replace ai with D(ai);
- SUM l r — calculate .
Print the answer for each SUM query.
分析:
我们考虑到每个数可以进行操作的数量不会很多,且D(1)=1,D(2)=2.
我们只需要暴力修改就行了,然后用树状数组求和.
如何优雅的暴力?
也就是说如何快速找出区间[l,r]内满足ai>2的i值.考虑用set维护还可以操作的下标的点,每次用lb,ub去找.暴力修改.
另外筛1-1e6中每个数的因子个数的方法需要注意.
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MAXN=3e5+7; 5 int N,M; 6 LL a[MAXN],val[MAXN]; 7 int D[1000001]; 8 inline int lowbit(int i){ 9 return i&-i; 10 } 11 LL sum(int x){ 12 LL res=0; 13 while(x){ 14 res+=a[x]; 15 x-=lowbit(x); 16 } 17 return res; 18 } 19 void add(int i,int x){ 20 while(i<=N){ 21 a[i]+=x; 22 i+=lowbit(i); 23 } 24 } 25 int getD(long long x){ 26 return D[x]; 27 } 28 int main(){ 29 for(int i=1;i<=1000000;++i){ 30 for(int j=i;j<=1000000;j+=i){ 31 D[j]++; 32 } 33 } 34 scanf("%d%d",&N,&M); 35 set<int>st; 36 for(int i=1;i<=N;++i){ 37 scanf("%I64d",&val[i]); 38 if(val[i]>2)st.insert(i); 39 add(i,val[i]); 40 } 41 while(M--){ 42 int t,l,r;scanf("%d%d%d",&t,&l,&r); 43 if(t==1){ 44 auto first=st.lower_bound(l); 45 auto last=st.upper_bound(r); 46 queue<int>q; 47 while(first!=last){ 48 int i=*first; 49 int x=getD(val[i]); 50 add(i,x-val[i]); 51 val[i]=x; 52 if(x<=2)q.push(i); 53 first++; 54 } 55 while(!q.empty()){ 56 int now=q.front();q.pop(); 57 st.erase(now); 58 } 59 }else{ 60 printf("%I64d\n",sum(r)-sum(l-1)); 61 } 62 } 63 return 0; 64 }