跳转至

LOJ-6277 数列分块入门1

Description

给定一个长为n的数列,以及n个操作,操作涉及区间加法、单点查询。

Input

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

对于100\% 的数据,1 \leq n \leq 50000,-2^{31} \leq \text { others, ans } \leq 2^{31}-11 \leq n \leq 50000,-2^{31} \leq \text { others, ans } \leq 2^{31}-11 \leq n \leq 50000,-2^{31} \leq \text { others, ans } \leq 2^{31}-11 \leq n \leq 50000,-2^{31} \leq \text { others, ans } \leq 2^{31}-1

Output

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

Sample Input

4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2

Sample Output

2
5

#include <bits/stdc++.h>

using namespace std;

int n, len; //数列长度,块的长度
vector<int> seq(50005); //存储数列元素
vector<int> belong(50005); //记录每个元素属于哪一个块
vector<int> addSign(50005); //加法标记

//区间加法
inline void add(int l, int r, int c)
{
    //左边不完整的块元素值直接改变
    for (int i = l; i <= min(belong[l] * len, r); ++i) seq[i] += c;
    //右边不完整的块元素值直接改变    
    if (belong[l] != belong[r]) { //确保l和r不在同一个块内
        for (int i = (belong[r] - 1) * len + 1; i <= r; ++i) seq[i] += c;
    }
    //改变中间整块的加法标记
    for (int i = belong[l] + 1; i <= belong[r] - 1; ++i) addSign[i] += c;
}

//单点查询
inline int query(int pos)
{
    return seq[pos] + addSign[belong[pos]];
}


int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> n;
    len = sqrt(n); //计算每个块的长度
    for (int i = 1; i <= n; ++i) {
        cin >> seq[i];
        belong[i] = (i - 1) / len + 1; //确定每个元素属于哪个块
    }

    int opt, l, r, c;
    for (int i = 0; i < n; ++i) {
        cin >> opt >> l >> r >> c;
        if (opt & 1) cout << query(r) << endl;
        else add(l, r, c);
    }

    return 0;
}