Problem A
发布时间: 2017年6月28日 09:29 最后更新: 2017年6月28日 13:03 时间限制: 1000ms 内存限制: 32M
给定一个长度为 n 的序列 a1 , a2 , ..., an
给出 q 个操作, 操作分为两种
对于形如 1 x y z 的操作, 将下标介于 [x,y] 的元素加上 z , 满足 1≤x≤y≤n , 1≤z≤105
对于形如 2 x 的操作, 输出 ax , 满足 1≤x≤n
9×104≤n≤105 , 9×104≤q≤105 , 1≤ai≤105
第一行两个整数
n
,
q
, 意义如上所述。
第二行
n
个整数, 表示序列
a
。
接下来
q
行, 每行第一个数为
opt
, 如果
opt=1
, 则后面紧跟三个数, 意义如上所述; 如果
opt=2
, 则后面紧跟一个数, 意义如上所述。
对于所有操作 2 , 输出答案, 一行一个。
8 3 3 1 4 1 5 9 2 6 2 3 1 2 3 6 2 3
4 10
题解:
由于树状数组的求和功能是可以在LOG(N)的时间复杂度内完成,现在我们考虑把求某一个点的值划归到求某一段区间和的问题,这样我们就可以构造序列
b[i] = a[i] - a[i-1],b[1] = a[i]
这样的话,如果我要把某段区间[l,r]的值增加val,那么我只需要把b[l]增加val,然后b[r+1]减去val,就可以了
代码:
#include <iostream>
#include <cstdio>
using namespace std;
#define int long long
const int MAX = 1e5+7;
int a[MAX];
int b[MAX];
int n,q;
int lowbit(int x){
return x&(-x);
}
int sum(int pos){
int ans = 0;
while(pos){
ans += b[pos];
pos -= lowbit(pos);
}
return ans;
}
void add(int pos,int val){
while(pos <= n){
b[pos] += val;
pos += lowbit(pos);
}
}
main(){
scanf("%lld%lld",&n,&q);
for(int i = 1;i <= n;i++){
scanf("%lld",&a[i]);
add(i,a[i]-a[i-1]);
}
while(q--){
int op;
scanf("%lld",&op);
if(op == 1){
int a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
add(a,c);
add(b + 1,-c);
}
else{
int a;
scanf("%lld",&a);
printf("%lld\n",sum(a));
}
}
return 0;
}