【线段树】 求和

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目:

Problem A: 线段树之Sum

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 187  Solved: 130
[Submit][Status][Web Board]

Description

给定一数列,规定有两种操作,一是修改某个元素,二是求区间的连续和。 
注意:初始序列全部为0。
输出时,只有k=1才输出,否则继续运行。

Input

输入数据第一行包含两个正整数n,m(n<=100000,m<=500000),以下是m行, 
每行有三个正整数k,a,b(k=0或1, a,b<=n).
k=0时表示将a处数字加上b,k=1时表示询问区间[a,b]内所有数的和。

Output

对于每个询问输出对应的答案。

Sample Input

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

Sample Output

10
6
0
6
16
6
24
14
50
41

HINT

 因为初始序列为0,所以不需要再来建树

此题为线段树模板题,

change(p,l,r,x,v)含义分别是:

p 代表当前树的编号 ,l 代表左序号,r 代表右序号,x 代表要修改的位置——即需要修改的序号,v 代表要修改的值

query(int p,int l,int r,int x,int y)含义分别是:

p 代表当前树的编号 ,l 代表当前左序号,r 代表当前右序号,x 代表查询左序号,y 代表查询右序号。

因为修改操作不需要输出答案,所以递归函数使用void   ,  查询操作要求输出答案,所以递归函数使用int

 code:

#include<bits/stdc++.h>
#define maxn 100000
#define maxnn 400000
using namespace std;
int n,m;
int a[maxn];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct segment{
    int sum[maxnn];
    #define ls p*2
    #define rs p*2+1
    #define mid (l+r)/2//注意:这里不能写成  #define mid l+r>>1 否则报错  
    segment(){memset(sum,0,sizeof(sum));}
    void update(int p){
        sum[p]=sum[ls]+sum[rs];//更新函数,依据题意为累加 
        //当前区间为下面两个子区间之和 
    }
    void build (int p,int l,int r){//建树 
        if(l==r){
            sum[p]=a[l];//当左边序号与右边序号相等时,就直接建树 
            return ;
        }
        build(ls,l,mid);//找左区间 
        build(rs,mid+1,r);//找右区间 
        update(p);//更新 
    }
    void change(int p,int l,int r,int x,int v){//更改操作(修改元素) 
        if(l==r&&l==x){//当左序号与右序号相等,并且要修改的位置x与左序号相等 
            sum[p]+=v;//依据题意:把a+b,即要修改的元素v加上 
            return ;
        }
        if(x<=mid)change(ls,l,mid,x,v);//当要修改的位置x在mid左时,就递归左区间 
        if(x>mid)change(rs,mid+1,r,x,v);//当要修改的位置在mid右时,就递归右区间 
        update(p);//更新 
    }
    int query(int p,int l,int r,int x,int y){//区间查询操作(统计答案) 
        if(l>y||r<x)return 0;//如果查询区间与当前区间完全无交集,直接return 0; 
        if(x<=l&&r<=y)return sum[p];//如果查询区间完全包含当前区间,直接返回当前值
//因为我们是先访问当前区间,再查询当前区间,相当于左右子区间的值即可表示其父亲区间 
     
        int ans=0;
        if(x<=mid)ans+=query(ls,l,mid,x,y);//查询 x →mid区间,并求和 
        if(y>mid)ans+=query(rs,mid+1,r,x,y);//查询 mid →y区间,并求和 
        update(p);//更新 
        return ans;//返回区间和的值        
    }
}kd;
int main(){
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
    a[i]=0;
    for(int i=1,k,a,b;i<=m;i++){
        k=read(),a=read(),b=read();
        if(k==0)kd.change(1,1,n,a,b);//从序号1开始,1~n为当前总序号,a为修改位置,b为需要修改的值
        if(k==1)printf("%d
",kd.query(1,1,n,a,b));//从序号1开始,1~n为当前总序号,a~b为查询序号
    }
    return 0;
}
原文地址:https://www.cnblogs.com/nlyzl/p/11341432.html