LOJ #6281. 数列分块入门 5

对于一个区间内开平方的复杂度是相当大的,但是只有当一个区间内有一个数 >=2 时才有资格开平方,所以添加一个数组来维护整个块是否需要开平方 

const int N=5e4+5;

    int i,j,k;
    int n,m,t;
    int a[N];
    int L[N],R[N];
    int bel[N],block,num,sum[N],all[N];

void build()
{
    block=sqrt(n);
    num=n/block; if(n%block) num++;
    for(int i=1;i<=num;i++){
        int l=(i-1)*block+1;
        int r=min(i*block,n);
        L[i]=l,R[i]=r;
        sum[i]=0,all[i]=0;
        for(int j=l;j<=r;j++){
            bel[j]=i,sum[i]+=a[j];
            if(a[j]>1) all[i]=1;
        }
    }
}

void renew(int fa)
{
    int l=L[fa],r=R[fa];
    sum[fa]=all[fa]=0;
    for(int i=l;i<=r;i++) sum[fa]+=a[i];
    for(int i=l;i<=r;i++){
        if(a[i]>1){ all[fa]=1; return ; }
    }
}

void update(int l,int r)
{
    int st=bel[l],en=bel[r];
    if(st==en){
        if(all[st]==0) return ;
        for(int i=l;i<=r;i++) a[i]=sqrt(a[i]);
        renew(st);
    } else{
        for(int i=l;i<=R[st];i++) a[i]=sqrt(a[i]);
        renew(st);
        for(int i=L[en];i<=r;i++) a[i]=sqrt(a[i]);
        renew(en);
        for(int i=st+1;i<=en-1;i++){
            if(all[i]==0) continue;
            for(int j=L[i];j<=R[i];j++) a[j]=sqrt(a[j]);
            renew(i);
        }
    }
}

int query(int l,int r)
{
    int ans=0;
    int st=bel[l],en=bel[r];
    if(st==en){
        for(int i=l;i<=r;i++) ans+=a[i];
    } else{
        for(int i=l;i<=R[st];i++) ans+=a[i];
        for(int i=L[en];i<=r;i++) ans+=a[i];
        for(int i=st+1;i<=en-1;i++) ans+=sum[i];
    }
    return ans;
}

int main()
{
    //IOS;
    while(~sd(n)){
        for(int i=1;i<=n;i++) sd(a[i]);
        build();
        while(n--){
            int opt=read(),x=read(),y=read(),w=read();
            if(opt) pd(query(x,y));
            else update(x,y);
        }
    }
    //PAUSE;
    return 0;
}

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页