• 线段树基础


    关于线段树的原理学习,可以参看杨弋大牛的论文《线段树》以及刘汝佳老师的《算法竞赛入门经典(训练指南)》,代码风格学习hzwer或者notonlysuccess均可。

    一.单点更新

    最基础的线段树

    题目:codevs1080

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

    分析:最简单的线段树,单点更新,区间求和

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int maxn=100000+10;
     5 struct data{
     6     int left,right; //左右端点
     7     int sum; //结点的和
     8 }Tree[maxn<<2];
     9 int n,m;
    10 int a[maxn];
    11 //建树过程
    12 void build(int l,int r,int rt){
    13     Tree[rt].left=l;Tree[rt].right=r;
    14     if(l==r){  //叶结点直接插入值
    15         Tree[rt].sum=a[l];
    16         return;
    17     }
    18     int mid=(l+r)>>1;
    19     build(l,mid,rt<<1);
    20     build(mid+1,r,rt<<1|1);
    21     Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
    22 }
    23 
    24 //单点更新
    25 void update(int x,int y,int rt){
    26     Tree[rt].sum+=y;
    27     int l=Tree[rt].left,r=Tree[rt].right;
    28     if(l==r) return;
    29     int mid=(l+r)>>1;
    30     if(x<=mid)  update(x,y,rt<<1);
    31     else update(x,y,rt<<1|1);
    32 }
    33 
    34 //区间求和
    35 int query(int l,int r,int rt){
    36     int L=Tree[rt].left,R=Tree[rt].right;
    37     if(L==l&&r==R){
    38         return Tree[rt].sum;
    39     }
    40     int mid=(L+R)/2;
    41     if(r<=mid) return query(l,r,rt<<1);
    42     if(l>mid) return query(l,r,rt<<1|1);
    43     return query(l,mid,rt<<1)+query(mid+1,r,rt<<1|1);
    44 }
    45 int main()
    46 {
    47     scanf("%d",&n);
    48     for(int i=1;i<=n;i++){
    49         scanf("%d",&a[i]);
    50     }
    51     build(1,n,1);
    52     scanf("%d",&m);
    53     while(m--){
    54         int num,x,y;
    55         scanf("%d%d%d",&num,&x,&y);
    56         if(num==1) update(x,y,1);
    57         else printf("%d
    ",query(x,y,1));
    58     }
    59     return 0;
    60 }
    View Code

    二.区间更新

    从单点更新一直到区间更新是初学者的一道坎,主要我们要深刻理解lazy操作,因为区间更新有时候并不需要像单点那样更新到子节点

    推荐一篇博客:http://blog.csdn.net/dreamzuora/article/details/52781831

    题目:codevs1082

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

    分析:区间更新,区间求和

     1 #include "iostream"
     2 #include "cstdio"
     3 #include "cstring"
     4 using namespace std;
     5 const int maxn=200000+10;
     6 struct data{
     7     int left,right;
     8     long long sum; //区间和
     9     int val;  //标记延迟
    10 }Tree[maxn<<2];
    11 int a[maxn];
    12 int n,m;
    13 
    14 //建树
    15 void build(int l,int r,int rt){
    16     Tree[rt].left=l;Tree[rt].right=r;
    17     if(l==r){
    18         Tree[rt].sum=a[l];
    19         return;
    20     }
    21     int mid=(l+r)>>1;
    22     Tree[rt].val=0;
    23     build(l,mid,rt<<1);
    24     build(mid+1,r,rt<<1|1);
    25     Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
    26 }
    27 
    28 //更新子节点
    29 void pushdown(int rt){
    30     int x=Tree[rt].right-Tree[rt].left+1;
    31     Tree[rt<<1].val+=Tree[rt].val;
    32     Tree[rt<<1|1].val+=Tree[rt].val;
    33     Tree[rt<<1].sum+=(x-(x>>1))*Tree[rt].val;
    34     Tree[rt<<1|1].sum+=(x>>1)*Tree[rt].val;
    35     Tree[rt].val=0;
    36 }
    37 
    38 //区间更新
    39 void update(int l,int r,int x,int rt){
    40     int L=Tree[rt].left,R=Tree[rt].right;
    41     if(L==l&&R==r){
    42         Tree[rt].val+=x;
    43         Tree[rt].sum+=(R-L+1)*x;
    44         return;
    45     }
    46     int mid=(L+R)>>1;
    47     if(Tree[rt].val) pushdown(rt);
    48     if(r<=mid) update(l,r,x,rt<<1);
    49     else if(l>mid)  update(l,r,x,rt<<1|1);
    50     else{
    51         update(l,mid,x,rt<<1);
    52         update(mid+1,r,x,rt<<1|1);
    53     }
    54     Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
    55 }
    56 
    57 //区间查询
    58 long long query(int l,int r,int rt){
    59     int L=Tree[rt].left,R=Tree[rt].right;
    60     if(L==l&&R==r){
    61         return Tree[rt].sum;
    62     }
    63     if(Tree[rt].val) pushdown(rt);
    64     int mid=(L+R)>>1;
    65     if(r<=mid) return query(l,r,rt<<1);
    66     if(l>mid) return query(l,r,rt<<1|1);
    67     return query(l,mid,rt<<1)+query(mid+1,r,rt<<1|1);
    68 }
    69 int main()
    70 {
    71     scanf("%d",&n);
    72     for(int i=1;i<=n;i++)
    73         scanf("%d",&a[i]);
    74     build(1,n,1);
    75     scanf("%d",&m);
    76     while(m--){
    77         int num;
    78         int x,y,d;
    79         scanf("%d",&num);
    80         if(num==1){
    81             scanf("%d%d%d",&x,&y,&d);
    82             update(x,y,d,1);
    83         }else{
    84             scanf("%d%d",&x,&y);
    85             printf("%lld
    ",query(x,y,1));
    86         }
    87     }
    88 }
    View Code
  • 相关阅读:
    echarts做飞线图
    git 检出项目部分目录(稀疏检出)
    nuxt.js引入客户端脚本和第三方库出现window/document/ navigator未定义问题
    防止重复发送 Ajax 请求
    利用CSS、JavaScript及Ajax实现图片预加载的三大方法
    JavaScript中this的指向问题
    掌握jQuery插件开发
    原生javascript实现图片放大镜效果
    javascript实现页面滚屏效果
    JavaScript利用闭包实现模块化
  • 原文地址:https://www.cnblogs.com/wolf940509/p/6523191.html
Copyright © 2020-2023  润新知