【线段树】区间求和

题目描述

给定一数列,规定有两种操作,一是修改某个元素,二是求区间的连续和。

输入

输入数据第一行包含两个正整数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

题解

这题是个模板题,只要注意节点初始值都为0。

#include
using namespace std; 
const int maxn=1e5+10;
#define ll long long 
ll sum[maxn*4];//要开四倍空间
ll query(int x,int y,int l,int r,int rt)
{
    if(x<=l&&y>=r)//如果当前的区间被要查询的区间包含,sum就直接取
        return sum[rt];
    ll ans=0;
    int mid=(l+r)/2;
    if(x<=mid)
        ans+=query(x,y,l,mid,2*rt);
    if(y>mid)
        ans+=query(x,y,mid+1,r,2*rt+1);
    return ans;
}
void update(int x,int y,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]+=y;
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid)
        update(x,y,l,mid,2*rt);
    else
        update(x,y,mid+1,r,2*rt+1);
    sum[rt]=sum[2*rt]+sum[2*rt+1];
}
void build(int l,int r,int rt)//编号rt节点包含的区间是[l,r]
{
    sum[rt]=0;//初始化为0
    if(l==r)
        return ;
    int mid=(l+r)/2;
    build(l,mid,2*rt);
    build(mid+1,r,2*rt+1);
    sum[rt]=sum[2*rt]+sum[2*rt+1];
}
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    build(1,n,1);
    while(m--)
    {
        int k,a,b;
        scanf("%d%d%d",&k,&a,&b);
        if(k==1)
        {
            printf("%lld\n",query(a,b,1,n,1));
        }
        else if(k==0)
        {
            update(a,b,1,n,1);
        }
    }
    return 0;
}

 

你可能感兴趣的:(算法)