codeforces CF920F SUM and REPLACE 线段树 线性筛约数

$ \Rightarrow $ 戳我进CF原题

F. SUM and REPLACE


time limit per test: 2 seconds
memory limit per test: 256 megabytes
input: standard input
output: standard output

 

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:
 
$ 1. REPLACE \quad l \quad r $ —— for every $ i \in [l,r] $ replace $ a_i $ with $ D(a_i) $ ;
$ 2. SUM \quad l \quad r $ —— calculate $ \sum_{i=l}^r a_i $ .
 
Print the answer for each $ SUM $ query.
 

Input

The first line contains two integers $ n $ and $ m (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 integers $ a_1, a_2, ..., a_n (1 ≤ ai ≤ 10^6) $ — the elements of the array.
 
Then $ m $ lines follow, each containing $ 3 $ integers $ t_i, l_i, r_i $ denoting $ i $ -th query.
If $ ti = 1 $ , then $ i $ -th query is $ REPLACE \quad l_i \quad r_i $ , otherwise it's $ SUM \quad l_i \quad r_i (1 ≤ t_i ≤ 2, 1 ≤ l_i ≤ r_i ≤ n) $ .
 
There is at least one $ SUM $ query.
 

Output

For each $ SUM $ query print the answer to it.
 

Examples

input

 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

output

 30
 13
 4
 22

 

题目大意

  • 给你 $ n $ 个数,进行 $ m $ 次操作,分别是将区间 $ [l,r] $ 内的所有数替换成自己的因子数 和 对区间 $ [l,r] $ 进行求和。

  • 数据范围: $ 1 \le n,m \le 3 \times 10^5 $
     

思路

  • 首先可以用线段树来维护序列,每次暴力修改。
    因为 $ D(1)=1, D(2)=2 $,因此当一个区间的最大值小于2时就不需要修改。
     
  • 又因为每次修改只会让值减少,而且每个数最多会被修改 $ O(log_n) $ 次,因此能够保证复杂度
     

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXM 1000005
#define N 300005
#define int long long
int n,m,M;
int d[MAXM],c[MAXM],p[MAXM];
bool vis[MAXM];
void pre(){
    d[1]=1;
    for(int i=2;i<=M;++i){
        if(!vis[i]){ p[++p[0]]=i; vis[i]=1; d[i]=2; c[i]=1; }
        for(int j=1;j<=p[0]&&1ll*i*p[j]<=M;++j){
            vis[i*p[j]]=1;
            if(i%p[j]==0){
                d[i*p[j]]=d[i]/(c[i]+1)*(c[i]+2);
                c[i*p[j]]=c[i]+1;
                break;
            }
            d[i*p[j]]=d[i]*2;
            c[i*p[j]]=1;
        }
    }
}
int sum[N<<2];
bool flag[N<<2];
void build(int o,int l,int r){
    if(l==r){
        scanf("%lld",&sum[o]);
        if(sum[o]==1||sum[o]==2) flag[o]=1;
        M=max(M,sum[o]);
        return;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    sum[o]=sum[o<<1]+sum[o<<1|1];
    flag[o]=flag[o<<1]&flag[o<<1|1];
}
void updata(int o,int l,int r,int L,int R){
    if(flag[o]) return;
    if(l==r&&L<=l&&l<=R){
        sum[o]=d[sum[o]];
        if(sum[o]==1||sum[o]==2) flag[o]=1;
        return;
    }
    int mid=l+r>>1;
    if(L>mid) updata(o<<1|1,mid+1,r,L,R);
    else if(R<=mid) updata(o<<1,l,mid,L,R);
    else {
        updata(o<<1,l,mid,L,R);
        updata(o<<1|1,mid+1,r,L,R);
    }
    sum[o]=sum[o<<1]+sum[o<<1|1];
    flag[o]=flag[o<<1]&flag[o<<1|1];	
}
int query(int o,int l,int r,int L,int R){
    if(L<=l&&r<=R) return sum[o];
    int mid=l+r>>1;
    if(L>mid) return query(o<<1|1,mid+1,r,L,R);
    else if(R<=mid) return query(o<<1,l,mid,L,R);
    else return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R);
}
signed main(){
    scanf("%lld %lld",&n,&m);
    build(1,1,n);
    pre();
    while(m--){
        int opt,x,y;
        scanf("%lld %lld %lld",&opt,&x,&y);
        if(opt==1) updata(1,1,n,x,y);
        else printf("%lld\n",query(1,1,n,x,y));
    }
    return 0;
}
/*
#          42607112 
When       2018-09-07 11:38:57 
Who        PotremZ 
Problem    F - SUM and REPLACE
Lang       GNU C++11 
Verdict    Accepted
Time       467 ms
Memory     35000 KB
*/
posted @ 2018-09-07 20:50  potrem  阅读(241)  评论(0编辑  收藏  举报