1. 程式人生 > >codeforces CF920F SUM and REPLACE 線段樹 線性篩約數

codeforces CF920F SUM and REPLACE 線段樹 線性篩約數

arrow 替換 input void set 範圍 HERE lld 數據

$ \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(logn) $ 次,因此能夠保證復雜度
     

代碼

#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
*/

codeforces CF920F SUM and REPLACE 線段樹 線性篩約數