时间限制: 1000 ms 内存限制: 524288 KB
提交数: 1175 通过数: 318
给定一数列,规定有两种操作,一是修改某个元素,二是求区间的连续和。
输入数据第一行包含两个正整数n,m(n≤100000,m≤500000),以下是m行,
每行有三个正整数k,a,b(k=0或1,a,b≤n).k=0时表示将a处数字加上b,k=1时表示询问区间[a,b]内所有数的和。
对于每个询问输出对应的答案。
10 20
0 1 10
1 1 4
0 6 6
1 4 10
1 8 9
1 4 9
0 10 2
1 1 8
0 2 10
1 3 9
0 7 8
0 3 10
0 1 1
1 3 8
1 6 9
0 5 5
1 1 8
0 4 2
1 2 8
0 1 1
10
6
0
6
16
6
24
14
50
41
#include
#define N 100000+5
#define LL long long
using namespace std;
int n,m,v;
LL a[N],t[4*N];//线段树必须为4*N 空间
//传入的参数为 k当前需要建立的结点;l当前需要建立的左端点;r当前需要建立的右端点
void build(int k,int L,int R) {
if (L==R) t[k]=a[L];//当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
else {
int mid = (L+R)/2;
build(k*2,L,mid);
build(k*2+1,mid+1,R);
t[k] = t[k*2] + t[k*2+1];//递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
}
}
//单点修改:
//k、l、r为当前更新到的结点、左右端点,
//x为需要修改的叶子结点左端点
//y为需要修改成的值;
void update(int k,int l,int r,int x,int y) {
if(l==r) {
a[x]+=y;
t[k]+=y;
return;
}
int mid=(l+r)/2;
if (x>=l&&x<=mid) update(k*2,l,mid,x,y);
else update(k*2+1,mid+1,r,x,y);
t[k]=t[k*2]+t[k*2+1];
}
LL query(int k,int l,int r,int x,int y) { //x、y为需要查询的区间左右端点
//若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值
//(如求和时返回0,求最大值时返回-1等)
if (x>r||y=r) return t[k];
int mid=(l+r)/2;
//p1为查询左儿子结点得到的信息,p2为查询右儿子结点得到的信息
LL p1=query(k*2,l,mid,x,y);
LL p2=query(k*2+1,mid+1,r,x,y);
return p1+p2;综合两个儿子结点的信息并返回return p1+p2
}
int main() {
scanf("%d%d",&n,&m);
//build(1,1,n);
while(m--) {
int k,a,b;
scanf("%d%d%d",&k,&a,&b);
if (k==0) {
update(1,1,n,a,b);
} else {
LL ans=query(1,1,n,a,b);
printf("%lld\n",ans);
}
}
return 0;
}