CF920F SUM and REPLACE(线段树+思维)

这题比较套路,首先我们发现,区间变成约数个数是不可能用区间维护的,因此这题显然有个trick

既然只能暴力修改单点,但是我们又要要求修改次数不能太多,因此可以联想到,是不是我约数个数求几次就变成一个常数了

继续观察,果然是这样,因此我们发现修改次数不会太多

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=1e6+10;
const int mod=1e9+7;
int a[N];
struct node{
    int l,r;
    int cnt;
    ll sum;
}tr[N<<2];
bool mark[N];
int prim[N],d[N],num[N];
int cnt;
void initial(){
    cnt=0;
    d[1]=1;
    for (int i=2;i<N;++i){
        if (!mark[i]){
            prim[cnt++]=i;
            num[i]=1;
            d[i]=2;
        }
        for (int j=0;j<cnt&&i*prim[j]<N;++j){
            mark[i*prim[j]]=1;
            if (!(i%prim[j])){
                num[i*prim[j]]=num[i]+1;
                d[i*prim[j]]=d[i]/(num[i]+1)*(num[i*prim[j]]+1);
                break;
            }
            d[i*prim[j]]=d[i]*d[prim[j]];
            num[i*prim[j]]=1;
        }
    }
}
void pushup(int u){
    tr[u].cnt=tr[u<<1].cnt+tr[u<<1|1].cnt;
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r,a[l]==1,a[l]};
    }
    else{
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int l,int r){
    ll x=tr[u].r-tr[u].l+1-tr[u].cnt;
    if(tr[u].sum-tr[u].cnt==x*2)
        return ;
    if(tr[u].l==tr[u].r){
        tr[u].sum=d[tr[u].sum];
        tr[u].cnt=(tr[u].sum==1)?1:0;
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
        modify(u<<1,l,r);
    if(r>mid)
        modify(u<<1|1,l,r);
    pushup(u);
}
ll query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].sum;
    }
    int mid=tr[u].l+tr[u].r>>1;
    ll ans=0;
    if(l<=mid)
        ans+=query(u<<1,l,r);
    if(r>mid)
        ans+=query(u<<1|1,l,r);
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    int i;
    initial();
    for(i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,n);
    while(m--){
        int opt;
        cin>>opt;
        int l,r;
        cin>>l>>r;
        if(opt==1){
            modify(1,l,r);
        }
        else{
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/14097102.html