zoukankan      html  css  js  c++  java
  • codevs 1082 线段树区间求和

    codevs 1082 线段树练习3

    链接:http://codevs.cn/problem/1082/

    sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值。

    我的线段树写法在运用的时候,需要更新或查找的区间是储存在y1,y2变量里面的,值是储存在变量v里面的,查询结果储存在变量_sum里面。

    每次更新(调用update函数)时,必须要维护更新区间上层的线段树,即更新节点上面的线段树表示的和是准确的和。

    在update函数更新的时候,如果线段树分成区间包含于所要求的区间那么直接在addv上记录下要加的值,否则再次细分区间。最后要再维护一下(调用pushdown函数),这样就保证了线段树的和性质。

    pushdown函数非常重要,在我的写法里,它有两个作用,一个是标记下放,另一个是结算和维护。注意在结算和的时候,要把左右儿子的addv和的也要加上去,否则会漏值。查询的时候也要用到pushdown,否则addv的值会在细分区间的时候漏掉,但查询(query函数)的pushdown不太样,要加入一个判断:只有当addv值不为0的时候才标记下放。如果不这样,本来一个对的值就会被重新计算,从而破坏了线段树的性质。

    附上代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #define LL long long int
     4 using namespace std;
     5 const int maxn=300010;
     6 
     7 LL n,k,A[maxn],sumv[maxn*4],addv[maxn*4];
     8 
     9 void init(int o,int L,int R)//初始化建树 
    10 {
    11     if(L==R) sumv[o]=A[L];
    12     else
    13     {
    14         int M=(L+R)/2;
    15         init(o*2,L,M);
    16         init(o*2+1,M+1,R);
    17         sumv[o]=sumv[o*2]+sumv[o*2+1];
    18     }
    19 }
    20 
    21 void pushdown(int o,int L,int R)//标记下放 
    22 {
    23     int M=(L+R)/2;
    24     if(L!=R) sumv[o]=sumv[o*2]+sumv[o*2+1]+addv[o]*(R-L+1)+addv[o*2]*(M-L+1)+addv[o*2+1]*(R-M);
    25     else sumv[o]+=addv[o];
    26     addv[o*2]+=addv[o];
    27     addv[o*2+1]+=addv[o];
    28     addv[o]=0;
    29 }
    30 
    31 int y1,y2,v;
    32 void update(int o,int L,int R)//更新 
    33 {
    34     if(y1<=L && R<=y2) addv[o]+=v;
    35     else
    36     {
    37         int M=(L+R)/2;
    38         if(y1<=M) update(o*2,L,M);
    39         if(y2>M) update(o*2+1,M+1,R);
    40     }
    41     pushdown(o,L,R);
    42 }
    43 
    44 LL _sum,p;
    45 void query(int o,int L,int R)//查询 
    46 {
    47     if(addv[o]!=0) pushdown(o,L,R);
    48     if(y1<=L && R<=y2) _sum+=sumv[o];
    49     else
    50     {
    51         int M=(L+R)/2;
    52         if(y1<=M) query(o*2,L,M);
    53         if(y2>M) query(o*2+1,M+1,R);
    54     }
    55 }
    56 
    57 int main()
    58 {
    59     cin>>n;
    60     for(int i=1;i<=n;i++) cin>>A[i];
    61     init(1,1,n);
    62     cin>>k;
    63     for(int i=1,tp,x,y,z;i<=k;i++)
    64     {
    65         cin>>tp;
    66         if(tp==1)
    67         {
    68             cin>>x>>y>>z;
    69             y1=x,y2=y,v=z;
    70             update(1,1,n);
    71         }
    72         else
    73         {
    74             cin>>x>>y;
    75             y1=x,y2=y,_sum=0;
    76             query(1,1,n);
    77             cout<<_sum<<endl;
    78         }
    79     }
    80     return 0;
    81  }
  • 相关阅读:
    Day 7 测试用例设计(二)场景流程分析法、正交表法、状态迁移法、
    Day 6 测试用例设计(一)等价类、边界值、判定表、因果图
    Day 5 网络基础 & SVN的使用
    Day 4 shell脚本
    gitlab-runner (一)
    大数据(二)Elasticsearch 分布式搜索引擎(存索引、索引搜索)
    大数据(一)from 北鼻 消息中间件 + 数据计算+数据存储=数据管理
    关系型数据库、非关系型数据库
    SVN 版本管理工具 Gitlab 仓库管理系统 Git 代码管理工具
    Day 2 & 3 linux常用命令, vim
  • 原文地址:https://www.cnblogs.com/frankscode/p/6239091.html
Copyright © 2011-2022 走看看