zoukankan      html  css  js  c++  java
  • 线段树

    线段树

    呃呃呃,两个月没写博客了。今天突然心血来潮,就把原来一篇只放了一个链接的线段树的博客删了,再写个新的。

     

    线段树,是一种二叉搜索树......这种介绍就不多说了,都是在百度上看的。放个链接自己去看吧。

    链接

    反正线段树就是一种比较牛逼的数据结构,可以快速解决区间里的某些问题。

    例如什么单点修改,单点查询,区间修改,区间查询......

    其实线段树的代码不是很难,主要就是把几个部分组合起来。

    在介绍这几个部分之前,先说一下两个贼好用的define,分别代表这个点的左儿子和右儿子。

    左儿子:#define lson l,m,rt<<1

    右儿子:#define rson m+1,r,rt<<1|1

    ①上传

    把左右儿子节点的信息传给父亲节点。

    1 void pushup(int rt){
    2     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
    3 }

    ②建树

    建造该线段树。具体过程为不断往下找左右儿子,直到一个儿子只包括一个节点,直接把值输入到该节点并改变所有与这个点相关的父亲节点。

     1 void build(int l,int r,int rt){
     2     if(l==r){
     3         scanf("%d",&tree[rt]);
     4         return;
     5     }
     6     int m=(l+r)>>1;
     7     build(lson);
     8     build(rson);
     9     pushup(rt);
    10 }

    ③更新

    改变一个点的值。具体过程为不断往下找左右儿子,直到一个儿子只包括一个节点,直接改变这个节点的值并改变所有与这个点相关的父亲节点。

     1 void update(int l,int r,int rt,int L,int R){
     2     if(l==r){
     3         tree[rt]+=R;
     4         return;
     5     }
     6     int m=(l+r)>>1;
     7     if(L<=m)
     8         update(lson,L,R);
     9     else
    10         update(rson,L,R);
    11     pushup(rt);
    12 }

    ④查询

    查询一个区间的值。具体过程为不断往下找左右儿子,直到一个儿子都包含在需要查询的区间内,直接返回这个儿子的值。

     1 int query(int l,int r,int rt,int L,int R){
     2     if(L<=l&&r<=R)
     3         return tree[rt];
     4     int m=(l+r)>>1,ans=0;
     5     if(L<=m)
     6         ans+=query(lson,L,R);
     7     if(m<R)
     8         ans+=query(rson,L,R);
     9     return ans;
    10 }

    最简单的线段树的基本代码就是这些,下面献上完整的代码。

     1 #include<cstdio>
     2 #define lson l,m,rt<<1
     3 #define rson m+1,r,rt<<1|1
     4 int tree[42521],n,m,a,b,c;
     5 void pushup(int rt){
     6     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
     7 }
     8 void build(int l,int r,int rt){
     9     if(l==r){
    10         scanf("%d",&tree[rt]);
    11         return;
    12     }
    13     int m=(l+r)>>1;
    14     build(lson);
    15     build(rson);
    16     pushup(rt);
    17 }
    18 void update(int l,int r,int rt,int L,int R){
    19     if(l==r){
    20         tree[rt]+=R;
    21         return;
    22     }
    23     int m=(l+r)>>1;
    24     if(L<=m)
    25         update(lson,L,R);
    26     else
    27         update(rson,L,R);
    28     pushup(rt);
    29 }
    30 int query(int l,int r,int rt,int L,int R){
    31     if(L<=l&&r<=R)
    32         return tree[rt];
    33     int m=(l+r)>>1,ans=0;
    34     if(L<=m)
    35         ans+=query(lson,L,R);
    36     if(m<R)
    37         ans+=query(rson,L,R);
    38     return ans;
    39 }
    40 int main(){
    41     scanf("%d%d",&n,&m);
    42     build(1,n,1);
    43     for(int i=1;i<=m;++i){
    44         scanf("%d%d%d",&a,&b,&c);
    45         if(a==1)
    46             update(1,n,1,b,c);
    47         else
    48             printf("%d
    ",query(1,n,1,b,c));
    49     }
    50     return 0;
    51 }
    完整代码

    不要问我数组大小为什么是42521,我是不会告诉你们的哈哈哈。

    不好意思我另一个人格又犯病了。

    没事没事咱们继续哈。

    求区间最小值,最大值等等的代码其实也差不多,只需要把查询和上传阶段稍加修改。

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define lson l,m,rt<<1
     5 #define rson m+1,r,rt<<1|1
     6 int tree[42521],n,m,a,b,c;
     7 void pushup(int rt){
     8     tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
     9 }
    10 void build(int l,int r,int rt){
    11     if(l==r){
    12         scanf("%d",&tree[rt]);
    13         return;
    14     }
    15     int m=(l+r)>>1;
    16     build(lson);
    17     build(rson);
    18     pushup(rt);
    19 }
    20 void update(int l,int r,int rt,int L,int R){
    21     if(l==r){
    22         tree[rt]=R;
    23         return;
    24     }
    25     int m=(l+r)>>1;
    26     if(L<=m)
    27         update(lson,L,R);
    28     else
    29         update(rson,L,R);
    30     pushup(rt);
    31 }
    32 int query(int l,int r,int rt,int L,int R){
    33     if(L<=l&&r<=R)
    34         return tree[rt];
    35     int m=(l+r)>>1,ans=424242521;
    36     if(L<=m)
    37         ans=min(ans,query(lson,L,R));
    38     if(m<R)
    39         ans=min(ans,query(rson,L,R));
    40     return ans;
    41 }
    42 int main(){
    43     scanf("%d%d",&n,&m);
    44     build(1,n,1);
    45     for(int i=1;i<=m;++i){
    46         scanf("%d%d%d",&a,&b,&c);
    47         if(a==1)
    48             update(1,n,1,b,c);
    49         else
    50             printf("%d
    ",query(1,n,1,b,c));
    51     }
    52     return 0;
    53 }
    最小值

    像我这种懒癌晚期是不会给你们再搞别的变形了,自己改去吧。

    上面只介绍了单点修改,那就再来说一下区间修改。

    区间修改比单点修改只多了一点,那就是懒标记。懒标记记录了这个区间都改变了什么,在每次修改或查询某区间时,都要考虑这个懒标记。

    ⑤标记

    标记这里其实并不复杂,就是把这个点的懒标记传给它的左右儿子,并更新它左右儿子的数值,最后清空这个点的懒标记。

    1 void pushdown(int rt,int RT){
    2     if(lazy[rt]==0)
    3         return;
    4     lazy[rt<<1]+=lazy[rt];
    5     tree[rt<<1]+=lazy[rt]*(RT-(RT>>1));
    6     lazy[rt<<1|1]+=lazy[rt];
    7     tree[rt<<1]+=lazy[rt]*(RT>>1);
    8     lazy[rt]=0;
    9 }

    除了懒标记,就没有别的什么了。

    那么就放上完整的代码吧。

     1 #include<cstdio>
     2 #define lson l,m,rt<<1
     3 #define rson m+1,r,rt<<1|1
     4 int tree[42521],lazy[42521],n,m,a,b,c,d;
     5 void pushup(int rt){
     6     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
     7 }
     8 void pushdown(int rt,int RT){
     9     if(lazy[rt]==0)
    10         return;
    11     lazy[rt<<1]+=lazy[rt];
    12     tree[rt<<1]+=lazy[rt]*(RT-(RT>>1));
    13     lazy[rt<<1|1]+=lazy[rt];
    14     tree[rt<<1]+=lazy[rt]*(RT>>1);
    15     lazy[rt]=0;
    16 }
    17 void build(int l,int r,int rt){
    18     if(l==r){
    19         scanf("%d",&tree[rt]);
    20         return;
    21     }
    22     int m=(l+r)>>1;
    23     build(lson);
    24     build(rson);
    25     pushup(rt);
    26 }
    27 void update(int l,int r,int rt,int L,int R,int RT){
    28     if(L<=l&&r<=R){
    29         lazy[rt]+=RT;
    30         tree[rt]+=RT*(r-l+1);
    31         return;
    32     }
    33     pushdown(rt,r-l+1);
    34     int m=(l+r)>>1;
    35     if(L<=m)
    36         update(lson,L,R,RT);
    37     if(m<R)
    38         update(rson,L,R,RT);
    39     pushup(rt);
    40 }
    41 int query(int l,int r,int rt,int L,int R){
    42     if(L<=l&&r<=R)
    43         return tree[rt];
    44     pushdown(rt,r-l+1);
    45     int m=(l+r)>>1,ans=0;
    46     if(L<=m)
    47         ans+=query(lson,L,R);
    48     if(m<R)
    49         ans+=query(rson,L,R);
    50     return ans;
    51 }
    52 int main(){
    53     scanf("%d%d",&n,&m);
    54     build(1,n,1);
    55     for(int i=1;i<=m;++i){
    56         scanf("%d",&a);
    57         if(a==1){
    58             scanf("%d%d%d",&b,&c,&d);
    59             update(1,n,1,b,c,d);
    60         }
    61         else{
    62             scanf("%d%d",&b,&c);
    63             printf("%d
    ",query(1,n,1,b,c));
    64         }
    65     }
    66     return 0;
    67 }
    又一个完整的代码
  • 相关阅读:
    poj2386 Lake Counting
    poj 1852 Ants
    Luogu P2419 [USACO08JAN]牛大赛Cow Contest
    Luogu P2336 [SCOI2012]喵星球上的点名
    Luogu P2463 [SDOI2008]Sandy的卡片
    Luogu P2852 [USACO06DEC]牛奶模式Milk Patterns
    Luogu P4248 [AHOI2013]差异
    【NOI2008】志愿者招募
    Luogu P2743 [USACO5.1]乐曲主题Musical Themes
    P3723 [AH2017/HNOI2017]礼物
  • 原文地址:https://www.cnblogs.com/jsawz/p/7418391.html
Copyright © 2011-2022 走看看