【滚动训练】LOJ6281. 数列分块入门 5 (分块)

本文介绍了一种处理区间操作的算法,包括区间开方和区间求和。通过预处理将数组分为多个块,并维护每个块的最小值和总和,以此来优化操作效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

给出一个长为 nn 的数列 a1an​​,以及 nn 个操作,操作涉及区间开方,区间求和。

题解

维护区间和。对于区间开方操作,维护区间最小值,若区间最小值小于等于1,那么就不需要进行操作。否则暴力更新区间最小值和区间和。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int nmax = 5e4+100;
const int INF = 0x3f3f3f3f;
const int mm = sqrt(5e4+100)+10;
int n,m;
ll data[nmax],mmax[mm],sum[mm];
int L[mm],R[mm],belong[nmax],num,block;
void init(){
    block = 2*sqrt(n);
    num = n / block; if(n % block) num++;
    for(int i = 1;i<=num;++i)
        L[i] = (i-1)*block+1,
        R[i] = i*block,
        mmax[i] = -INF;
    R[num] = n;
}
int main() {
    scanf("%d",&n);
    init();
    for(int i = 1;i<=n;++i){
        scanf("%lld",&data[i]);
        belong[i] = (i-1) / block + 1;
        mmax[belong[i]] = max(mmax[belong[i]],data[i]);
        sum[belong[i]] += data[i];
    }
    int l,r,op; ll w;
    for(int i = 1;i<=n;++i){
        scanf("%d %d %d %lld",&op,&l,&r,&w);
        if(op == 0){
            if(mmax[belong[l]] > 1){
                for(int j = l;j<=min(r,R[belong[l]]);++j) data[j] = sqrt(data[j]);
                mmax[belong[l]] = -INF, sum[belong[l]] = 0;
                for(int j = L[belong[l]];j<=R[belong[l]];++j)
                    mmax[belong[l]] = max(mmax[belong[l]],data[j]),
                    sum[belong[l]] += data[j];
            }
            if(belong[r] != belong[l] && mmax[belong[r]] > 1){
                for(int j = L[belong[r]];j<=r;++j) data[j] = sqrt(data[j]);
                mmax[belong[r]] = -INF, sum[belong[r]] = 0;
                for(int j = L[belong[r]];j<=R[belong[r]];++j){
                    mmax[belong[r]] = max(mmax[belong[r]],data[j]);
                    sum[belong[r]] += data[j];
                }
            }
            for(int j = belong[l] + 1;j<=belong[r]-1;++j){
                if(mmax[j] > 1){
                    mmax[j] = -INF, sum[j] = 0;
                    for(int k = L[j];k<=R[j];++k){
                        data[k] = sqrt(data[k]);
                        mmax[j] = max(mmax[j],data[k]);
                        sum[j] += data[k];
                    }
                }
            }
        }else{
            ll ans = 0;
            for(int j = l;j<=min(r,R[belong[l]]);++j) ans += data[j];
            if(belong[r] != belong[l] )for(int j = L[belong[r]];j<=r;++j) ans += data[j];
            for(int j = belong[l]+1;j<=belong[r]-1;++j) ans += sum[j];
            printf("%lld\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值