题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某区间每一个数数加上 x;
求出某一个数的值。
输入格式
第一行包含两个整数 N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 M 行每行包含 2 或 4个整数,表示一个操作,具体如下:
操作 1: 格式:
1 x y k
含义:将区间 [x,y]内每个数加上k;操作 2: 格式:
2 x
含义:输出第 x 个数的值。输出格式
输出包含若干行整数,即为所有操作 2 的结果。
输入样例
5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4输出样例
6
10数据规模
1≤N,M≤500000,1≤x,y≤n,保证任意时刻序列中任意元素的绝对值都不大于 2^30。
参考思路
我们构建差分,然后将差分都存进sum数组里面,形成一个前缀和数组,当询问时直接输出树状sum数组1-i 之和即可。
参考代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<sstream>
#include<string>
#include<map>
using namespace std;
typedef long long ll;
int dx[4] = { 0, 0, 1, -1 };
int dy[4] = { 1, -1, 0, 0 };
#define fo(i,l,r) for (int i = l; i <= r; ++i)
#define F 1500005
int n, m, a[F], sum[F], k, x, y, j;
int C(int x)
{
return x & (-x);
}
void add(int x, int k)
{
while (x <= n)
{
sum[x] += k;
x = x + C(x);
}
}
int ask(int x)
{
int ans = 0;
while (x > 0)
{
ans += sum[x];
x -= C(x);
}
return ans;
}
int main()
{
int t;
cin >> n >> m;
int last = 0;
fo(i, 1, n)//构建差分序列之前缀和 用来维护区间加 求单点值
{
scanf("%d", &t); add(i, t - last); last = t;
}
while (m--)
{
scanf("%d", &j);
if (j == 1)
{
scanf("%d%d%d", &x, &y, &k); add(x, k); add(y + 1, -k);
}
else
{
scanf("%d", &x);
cout << ask(x) << endl;
}
}
return 0;
}
>>