洛谷 P13976:数列分块入门 1 ← 序列分块算法(区间更新、单点查询)

【题目来源】
https://www.luogu.com.cn/problem/P13976

【题目描述】
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。

【输入格式】
第一行输入一个数字 n。
第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。
接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt=0,表示将位于 [l,r] 的之间的数字都加 c。
若 opt=1,表示询问 ar 的值(l 和 c 忽略)。

【输出格式】
对于每次询问,输出一行一个数字表示答案。

【输入样例】
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0​​​​​​​

【输出样例】
2
5

【数据范围】
对于所有数据,1≤n≤300000,−2^63≤ai,c,ans≤2^63−1。

【算法分析】
● “序列分块”算法的基本要素及 build() 函数的构建细节:https://blog.csdn.net/hnjzsyjyj/article/details/138955263

【算法代码:1-based】
本题推荐 1-based 写法。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N=3e5+5;
LL a[N],le[N],ri[N];
int pos[N];
LL lazy[N];
int n;

void build() { //1-based
    int block=sqrt(n);
    int cnt=(n+block-1)/block;
    for(int i=1; i<=cnt; i++) {
        le[i]=(i-1)*block+1;
        ri[i]=i*block;
    }
    ri[cnt]=n;
    for(int i=1; i<=n; i++) pos[i]=(i-1)/block+1;
}

void add(int st,int ed,LL val) {
    if(pos[st]==pos[ed]) {
        for(int i=st; i<=ed; i++) a[i]+=val;
        return;
    }
    for(int i=st; i<=ri[pos[st]]; i++) a[i]+=val;
    for(int i=pos[st]+1; i<pos[ed]; i++) lazy[i]+=val;
    for(int i=le[pos[ed]]; i<=ed; i++) a[i]+=val;
}

LL query(int x) {
    return a[x]+lazy[pos[x]];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    for(int i=1; i<=n; i++) cin>>a[i];

    build();

    while(n--) {
        int op,le,ri;
        LL val;
        cin>>op>>le>>ri>>val;
        if(op==0) {
            add(le,ri,val);
        } else {
            cout<<query(ri)<<"\n";
        }
    }

    return 0;
}

/*
in:
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0

out:
2
5
*/

【算法代码:0-based】

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N=3e5+5;
LL a[N],le[N],ri[N];
int pos[N];
LL lazy[N];
int n;

void build() {
    int block=sqrt(n);
    int cnt=(n+block-1)/block;
    for(int i=0; i<cnt; i++) {
        le[i]=i*block;
        ri[i]=(i+1)*block-1;
    }
    ri[cnt-1]=n-1;
    for(int i=0; i<n; i++) pos[i]=i/block;
}

void add(int st,int ed,LL val) {
    if(pos[st]==pos[ed]) {
        for(int i=st; i<=ed; i++) a[i]+=val;
        return;
    }
    for(int i=st; i<=ri[pos[st]]; i++) a[i]+=val;
    for(int i=pos[st]+1; i<pos[ed]; i++) lazy[i]+=val;
    for(int i=le[pos[ed]]; i<=ed; i++) a[i]+=val;
}

LL query(int x) {
    return a[x]+lazy[pos[x]];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    for(int i=0; i<n; i++) cin>>a[i];

    build();

    while(n--) {
        int op,le,ri;
        LL val;
        cin>>op>>le>>ri>>val;
        if(op==0) {
            add(le-1,ri-1,val);
        } else {
            cout<<query(ri-1)<<"\n";
        }
    }

    return 0;
}

/*
in:
4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0

out:
2
5
*/



【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/138955263

 

posted @ 2026-07-16 15:10  Triwa  阅读(5)  评论(0)    收藏  举报