题目描述
输入格式
输出格式
对于每个
2 l r
操作输出一行,每行有一个整数,表示所求的结果。
样例输入
3 2 1 2 3 1 2 0 2 1 3
样例输出
6
题目分析:这应该是一道最基本的线段树了,就是对区间上的修改和求和,我写的代码也是从网上找的模板,建树的时候是递归到最底层也就是叶子节点,然后向上回溯,每一个节点都记录了一段区间以及区间的和。区间修改和建树几乎是一样的,如果想再优化的话可以用懒惰标记,就是延时修改,差不多这意思。求区间和跟之前的类似,都是一个道理的呐!!!
代码如下
#include<bits/stdc++.h>
using namespace std;
struct node
{
int l,r;
long long sum,poi;
}tree[4040400];
int n,m;
int c,l,r,x;
long long d;
int i;
long long a[1010100];
void build(int p,int l,int r) // 建树
{
tree[p].l=l;tree[p].r=r;
if (l==r) {
tree[p].sum=a[l];
return;
}
int mid=(l+r)/2;
if (l<=mid) build(p*2,l,mid);
if (r>mid) build(p*2+1,mid+1,r);
tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}
void spread(int p)
{
if (tree[p].poi)
{
tree[p*2].sum+=(tree[p*2].r-tree[p*2].l+1)*tree[p].poi;
tree[p*2+1].sum+=(tree[p*2+1].r-tree[p*2+1].l+1)*tree[p].poi;
tree[p*2].poi+=tree[p].poi;
tree[p*2+1].poi+=tree[p].poi;
tree[p].poi=0;
}
}
void change(int p,int l,int r,long long d)// 区间修改
{
if (l<=tree[p].l&&tree[p].r<=r)
{
tree[p].sum+=(tree[p].r-tree[p].l+1)*d;
tree[p].poi+=d;
return;
}
spread(p);
int mid=(tree[p].l+tree[p].r)/2;
if (l<=mid) change(p*2,l,r,d);
if (r>mid) change(p*2+1,l,r,d);
tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
}
long long ask(int p,int l,int r) //区间查询
{
if (l>tree[p].r||r<tree[p].l) return 0;
if (l<=tree[p].l&&tree[p].r<=r)
return tree[p].sum;
spread(p);
int mid=(tree[p].l+tree[p].r)/2;
long long val=0;
if (l<=mid) val+=ask(p*2,l,r);
if (r>mid) val+=ask(p*2+1,l,r);
return val;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&c,&l,&r);
if (c==1)
{
//scanf("%lld",&d);
change(1,l,l,r);
}
else
printf("%lld\n",ask(1,l,r));
}
return 0;
}