题面

题意:

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;
}

完美撒花✿✿ヽ(°▽°)ノ✿