zoukankan      html  css  js  c++  java
  • 【线段树】 求和

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

    本蒟蒻谢谢大家观看

    题目:

    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;
    }
  • 相关阅读:
    个人常用Git操作记录
    JavaScript引擎基本原理:Shapes和Inline Caches
    Promise.then(a, b)与Promise.then(a).catch(b)问题详解
    p标签中的文本换行
    Vue初始化
    关于vue的源码调试
    关于extjs表单布局的几种方式
    sublime text3安装、注册及常用插件
    chrome扩展程序开发
    关于Git的简单使用
  • 原文地址:https://www.cnblogs.com/nlyzl/p/11341432.html
Copyright © 2011-2022 走看看