描述
如题,已知一个数列,你需要进行下面两种操作:
-
将某一个数加上x
-
求出某区间每一个数的和
输入
第一行包含两个正整数n,m,分别表示该数列数字的个数和操作的总个数。
第二行包含n个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来m行每行包含3个整数,表示一个操作,具体如下:
-
1 x k
含义:将第x个数加上k -
2 x y
含义:输出区间[x,y]内每个数的和
输出
输出包含若干行整数,即为所有操作2的结果。
输入样例 1
5 5 1 5 4 2 3 1 1 3 2 2 5 1 3 -1 1 4 2 2 1 4
输出样例 1
14 16
提示
1<=(n,m,k)<=5e5
1<=x<=y<=n
#include <iostream>
#define int long long
using namespace std;
const int N = 5e5+10;
struct segmentTree
{
int l,r;
int sum;
} t[N<<2];
int a[4*N];
void pushup(int p)//向上更新,修改某个节点后,将所有祖先节点中存储的信息都更新一遍
{
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
void build(int p,int l,int r)//构建整颗线段树
{
t[p]={l,r};//记录当前节点的左右端点
if(l==r)
{
t[p].sum=a[l];//将该节点存储的信息设为对应位置上的函数值
return;
}
//如果不是叶子节点就继续递归构建它的左右子节点
int mid=(l+r)>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
pushup(p);//最后更新当前节点的信息
}
void modify(int p,int v,int k)//修改线段树中某个位置上的函数
// p为当前需要修改的结点的编号
//v为要修改的元素的下标
//k为要加上的函数值
{
if(t[p].l==t[p].r&&t[p].l==v)
{
t[p].sum+=k;
return;
}
int mid=(t[p].l+t[p].r)>>1;//继续向它的子节点中搜索
if(v<=mid) modify(p<<1,v,k);//修改左子节点的信息
else modify(p<<1|1,v,k);//修改右子节点的信息
pushup(p);//更新祖先节点的信息
}
int query(int p,int l,int r)//查询某个区间的信息,l和r表示需要查询的区间
{
if(t[p].r<=r&&t[p].l>=l)//先判断前节点的区间是否包含要查询的区间
{
return t[p].sum;
}
int mid=(t[p].l+t[p].r)>>1;
int res=0;
if(r<=mid) res+=query(p<<1,l,r);
else if(l>mid) res+=query(p<<1|1,l,r);
else res+=query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
return res;
}
signed main()
{
int n,m;
cin >> n >> m;
for(int i = 1;i <= n;i ++)
{
cin >> a[i];
}
build(1,1,n);
while(m --)
{
int op;
cin >> op;
if(op==1)
{
int x,k;
cin >> x >> k;
modify(1,x,k);
}
else
{
int l,r;
cin >> l >> r;
printf("%lld\n",query(1,l,r));
}
}
}