LOJ #6281. 数列分块入门 5

9 篇文章 1 订阅

对于一个区间内开平方的复杂度是相当大的,但是只有当一个区间内有一个数 >=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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值