#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<set> #define ll long long #define maxn 300005 #define maxm 1000000 using namespace std; set<int> s; set<int> ::iterator it; int zs[maxn],t=0,low[maxm+5]; int d[maxm+5],n,m,le,ri,opt; bool v[maxm+5]; int a[maxn]; ll f[maxn],qz[maxn]; inline void init(){ d[1]=1,low[1]=1; for(int i=2;i<=maxm;i++){ if(!v[i]) zs[++t]=i,d[i]=2,low[i]=i; for(int j=1,u;j<=t&&(u=zs[j]*i)<=maxm;j++){ v[u]=1; if(!(i%zs[j])){ low[u]=low[i]*zs[j]; if(low[i]==i) d[u]=d[i]+1; else d[u]=d[low[u]]*d[i/low[i]]; break; } low[u]=zs[j],d[u]=d[i]<<1; } } } inline void update(int x,int y){ for(;x<=n;x+=x&-x) f[x]+=(ll)y; } inline ll query(ll x){ ll an=0; for(;x;x-=x&-x) an+=f[x]; return an; } inline void solve(){ int pre=*s.lower_bound(le); while(pre<=ri){ update(pre,d[a[pre]]-a[pre]); a[pre]=d[a[pre]]; if(a[pre]<=2) s.erase(pre); pre=*s.upper_bound(pre); } } int main(){ init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",a+i); qz[i]=qz[i-1]+(ll)a[i]; s.insert(i); } s.insert(n+1); while(m--){ scanf("%d%d%d",&opt,&le,&ri); if(opt==2) printf("%lld\n",qz[ri]-qz[le-1]+query(ri)-query(le-1)); else solve(); } return 0; }
题目描述
Let D(x) D(x) be the number of positive divisors of a positive integer x x . For example, D(2)=2 D(2)=2 ( 2 2 is divisible by 1 1 and 2 2 ), D(6)=4 D(6)=4 ( 6 6 is divisible by 1 1 , 2 2 , 3 3 and 6 6 ).
You are given an array a a of n n integers. You have to process two types of queries:
REPLACE l l r r — for every replace a_{i} a
i
? with D(a_{i}) D(a
i
? ) ;
SUM l l r r — calculate .
Print the answer for each SUM query.
输入输出格式
输入格式:
The first line contains two integers n n and m m ( 1<=n,m<=3·10^{5} 1<=n,m<=3?10
5
) — the number of elements in the array and the number of queries to process, respectively.
The second line contains n n integers a_{1} a
1
? , a_{2} a
2
? , ..., a_{n} a
n
? ( 1<=a_{i}<=10^{6} 1<=a
i
? <=10
6
) — the elements of the array.
Then m m lines follow, each containing 3 3 integers t_{i} t
i
? , l_{i} l
i
? , r_{i} r
i
? denoting i i -th query. If t_{i}=1 t
i
? =1 , then i i -th query is REPLACE l_{i} l
i
? r_{i} r
i
? , otherwise it‘s SUM l_{i} l
i
? r_{i} r
i
? ( 1<=t_{i}<=2 1<=t
i
? <=2 , 1<=l_{i}<=r_{i}<=n 1<=l
i
? <=r
i
? <=n ).
There is at least one SUM query.
输出格式:
For each SUM query print the answer to it.
输入输出样例
输入样例#1:
7 6
6 4 1 10 3 2 4
2 1 7
2 4 5
1 3 5
2 4 4
1 5 7
2 1 7
输出样例#1:
30
13
4
22
可以发现每个数被改若干次之后就会变成2(或者这个数本来就为1它也只能是1),而这个次数的最大值也不会很大,所以我们就可以维护一个还没有变成≤2的位置集合,然后暴力单点修改。又因为是求前缀和,所以我们再维护一个树状数组就好了,时间复杂度O(N*log2N)