CF920F 【SUM and REPLACE】
题意:
1:将 [l,r]区间内的所有数变为当前权值的正约数的个数,即:\(a_i\)=d(a_i)
2:求\(\displaystyle \sum_{i=l}^{r}a_{i}\)
前置芝士:
求\(d(i)\)的话,可以先康康这个题P6810 「MCOI-02」Convex Hull 凸包
这个题中就是线性筛处理出了每个数的约数的个数
这里安利一个同机房dalao的博客
我们就可以发现每个数的约数的个数就可以处理出来了
void make_d(){
d[1] = f[1] = 1;
for(int i = 2; i <= M - 5; i ++){
if(!is_pri[i]){
pri[++ cnt] = i;
f[i] = 1;
d[i] = 2;
}
for(int j = 1; j <= cnt && i * pri[j] <= M - 5; j ++){
is_pri[i * pri[j]] = 1;
if(i % pri[j] == 0){
f[i * pri[j]] = f[i] + 1;
d[i * pri[j]] = (d[i]) * (f[i * pri[j]] + 1) / (f[i] + 1);
break;
}
f[i * pri[j]] = 1;
d[i * pri[j]] = d[i] * d[pri[j]];
}
}
}
实现:
我们先用线性筛筛出每个数的约数的个数
然后维护一棵线段树,线段树维护一个区间\(sum\)和区间最大值
我们考虑当\(i=1或2\)的时候,\(d(i)\)是等于\(i\)的,所以不用修改
所以当区间最大值\(<=2\)的时候,我们就可以不对这个区间进行任何修改操作了(因为操作了也没有任何意义)
然后就是维护一棵普通的线段树就好了
但是这个题要注意开$long\ long $,不然会炸的
代码:
#include<bits/stdc++.h>
using namespace std;
#define ls(o) (o << 1)
#define rs(o) (o << 1 | 1)
#define mid ((l + r) >> 1)
const int N = 3e5 + 5, M = 1e6 + 5;
int n, m, a[N], pri[N], cnt;
long long mx[N << 2], tr[N << 2], d[M], f[M];
bool is_pri[M];
void make_d(){
d[1] = f[1] = 1;
for(int i = 2; i <= M - 5; i ++){
if(!is_pri[i]){
pri[++ cnt] = i;
f[i] = 1; d[i] = 2;
}
for(int j = 1; j <= cnt && i * pri[j] <= M - 5; j ++){
is_pri[i * pri[j]] = 1;
if(i % pri[j] == 0){
f[i * pri[j]] = f[i] + 1;
d[i * pri[j]] = (d[i]) * (f[i * pri[j]] + 1) / (f[i] + 1);
break;
}
f[i * pri[j]] = 1;
d[i * pri[j]] = d[i] * d[pri[j]];
}
}
}
void up(int o){
tr[o] = tr[ls(o)] + tr[rs(o)];
mx[o] = max(mx[ls(o)], mx[rs(o)]);
}
void build(int o, int l, int r){
if(l == r){
scanf("%d", &tr[o]);
mx[o] = tr[o];
return ;
}
build(ls(o), l, mid); build(rs(o), mid + 1, r);
up(o);
}
void change(int o, int l, int r, int L, int R){
if(mx[o] <= 2) return ;
if(l == r){
tr[o] = mx[o] = d[tr[o]];
return ;
}
if(L <= mid) change(ls(o), l, mid, L, R);
if(R > mid) change(rs(o), mid + 1, r, L, R);
up(o);
}
long long query(int o, int l, int r, int L, int R){
if(L <= l && r <= R) return tr[o];
long long res = 0;
if(L <= mid) res += query(ls(o), l, mid, L, R);
if(R > mid) res += query(rs(o), mid + 1, r, L, R);
return res;
}
int main(){
scanf("%d %d", &n, &m);
make_d(); build(1, 1, n);
for(int i = 1, opt, l, r; i <= m; i ++){
scanf("%d %d %d", &opt, &l, &r);
if(opt == 1) change(1, 1, n, l, r);
else printf("%lld\n", query(1, 1, n, l, r));
}
return 0;
}
完美撒花✿✿ヽ(°▽°)ノ✿