codeforces CF920F SUM and REPLACE 線段樹 線性篩約數
$ \Rightarrow $ 戳我進CF原題
F. SUM and REPLACE
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.
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 線段樹 線性篩約數