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.
The first line contains two integers n and m (1 ≤ n, m ≤ 3·105) — the number of elements in the array and the number of queries to process, respectively.
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106) — the elements of the array.
Then m lines follow, each containing 3 integers ti, li, ri denoting i-th query. If ti = 1, then i-th query is REPLACE li ri, otherwise it's SUM li ri (1 ≤ ti ≤ 2, 1 ≤ li ≤ ri ≤ n).
There is at least one SUM query.
For each SUM query print the answer to it.
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
30 13 4 22
题意:给出一个数组,有两个操作,一个操作把区间所有数都变成其因子个数,另一个操作询问区间和。
思路:线段树。先预处理因子个数,并且需要注意如果线段树某一重复段一直更新,而一个数变为它因子数这个操作经过一定次数后,这个数不会再变化,这会是很大的浪费。通过预先计算得最大次数为6。节点中加一个更改次数的标志,大于一定数后就不在进行更新操作所以这样大大降低的时间。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define L(x) (x << 1)//左儿子
#define R(x) (x << 1 | 1)//右儿子
#define sz(x) (tree[x].r - tree[x].l + 1)//区间大小
#define maxm 1000005
using namespace std;
typedef long long ll;
const ll MAXN = 300005;
ll n,m,a,b,c,num[MAXN];
int yz[maxm];
int chge[maxm];
string t;
// l == 左;r == 右;p == now;
struct tree{
ll l,r,sum,tim;//修改求和
}tree[MAXN << 2];
//标记下放们 p == now
void update(ll p){
tree[p].sum = tree[L(p)].sum + tree[R(p)].sum;
}
//简单的建立
void build(ll l,ll r,ll p){
tree[p].tim=0;
tree[p].l = l,tree[p].r = r;
if(l == r){
tree[p].sum = num[l];
return;
}
ll mid = (tree[p].l + tree[p].r) >> 1;
build(l,mid,L(p)); build(mid + 1,r,R(p));
update(p);
}
//区间修改
void change(ll l,ll r,ll p){
if(tree[p].l>=l&&tree[p].r<=r)
{
if(tree[p].tim>=10)
return;
tree[p].tim++;
}
if(tree[p].l==tree[p].r)
{
tree[p].sum=yz[num[tree[p].l]];
num[tree[p].l]=yz[num[tree[p].l]];
return;
}
ll mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid) change(l,r,L(p));
if(mid < r) change(l,r,R(p));
update(p);
}
//区间求和
ll ask_sum(ll l,ll r,ll p){
if(l <= tree[p].l && tree[p].r <= r)
return tree[p].sum;
ll ans = 0,mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid) ans += ask_sum(l,r,L(p));
if(mid < r) ans += ask_sum(l,r,R(p));
update(p); return ans;
}
int YinZi(int n)
{
int ans=1;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
int num=0;
while(n%i==0)
{
num++;
n=n/i;
}
ans*=(num+1);
}
}
if(n>1)
ans*=2;
return ans;
}
void init()
{
memset(yz,0,sizeof(yz));
for(int i=1;i<maxm;i++)
{
yz[i]=YinZi(i);
chge[i]=yz[i]-i;
}
}
/*
int maxx=0;
int dp[maxm];
void hh()
{
dp[1]=0;
dp[2]=0;
dp[3]=1;
for(int i=4;i<maxm;i++)
{
dp[i]=dp[yz[i]]+1;
maxx=max(maxx,dp[i]);
}
cout<<maxx<<endl;
}
*/
int main()
{
init();
// hh();
while(~scanf("%d%d",&n,&m))
{
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
{
scanf("%I64d",&num[i]);
}
build(1,n,1);
int op,l,r;
while(m--)
{
scanf("%d%d%d",&op,&l,&r);
if(op==1)
{
change(l,r,1);
}
else
{
printf("%I64d\n",ask_sum(l,r,1));
}
}
}
}