• 线段树整理


    终于学完了线段树,没学之前觉得特牛x,看了好几位dalao的博客,就整理一下,增强理解记忆ovo。

    一、引入

    线段树是一个数据结构。数据结构是先有需求,后有数据结构,用来将数据进行处理,达到优化的目的。(闵学长讲题步骤:先暴力,后用数据结构优化)。

    问题:

    给出n个数,n<=**,和m个询问,每次询问区间[l,r]的和,并输出。

    一般思路,先暴力。就挨个枚举呗。可是当**很大的时候呢,就容易超时。这时我们就有了需求,需要想一个数据结构来优化我们的算法。

    就有了线段树这个数据结构。

    二、概念

    什么是线段树呢?顾名思义,树上存着线段呗。以前我们树上的每一个结点存的是权值,现在,我们的每一个结点上存的是每一个区间的信息。

    线段树是一个高效处理动态区间的查询问题。线段树的主要思想是二分。

    如图,我们要对区间0--5进行一系列访问,结点1存0--5区间的信息,然后将这个区间二分为0--2和3--5,它的左孩子存0--2区间的信息,右孩子存3--5区间的信息。

    依次这样推下去。线段树的几种用法:建树 单点查询 单点修改 区间查询 区间修改 

    三、用法

    (1)建树:

    用一个结构体 存每一个结点存的区间的左端点和右端点 叶子结点的val存其本身的的值 不是叶子结点存其区间的和。

    建树的过程是一个递归的过程。

    //构建线段树 
    const int maxn=1000;
    struct segTreenode
    {
        int val,l,r,s;
    }segTree[maxn*4];//大小*4 先这么记吧 具体我也没搞懂
    void build(int root,int l,int r)//线段树的当前结点和当前结点的左右区间 
    {
        segTree[root].l=l;segTree[root].r=r; 
        if(segTree[root].l==segTree[root].r)//是叶子结点 
        {
            scanf("%d",&segTree[root].val);
            return;//不必递归 
        }
          int m=(l+r)>>1;//区间的中间值 
          build(root*2,l,m);//建左子树 
          build(root*2+1,m+1,r);//建右子树 
          segTree[root].val=segTree[root*2].val+segTree[root*2+1].val;//当前值为左右子树的和 
    }

    (2)单点查询

    思想和二分找一个数差不多 只是看看这个数在当前点的左子树还是右子树

    //询问单个点的状态; 
    void ask(int k)
    {
        if(segTree[k].l==segTree[k].r)//是叶子结点
        {
            ans=segTree[k].val;
            return;//一定要return 不必递归
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)ask(k*2);//找左子树
        if(x>m)ask(k*2+1);//找右子树
    }

    (3)修改单点

    //修改单点
    void change_point(int k)
    {
        if(segTree[k].l==segTree[k].r)//找到叶子
        {
            segTree[k].val+=w;
            return;
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)change_point(k*2);
        else change_point(k*2+1);
        segTree[k].val=segTree[k*2].val+segTree[k*2+1].val;//修改val,因为区间和已经改变

    (4)区间查询 

    求一个区间的和 只是将他的子区间的和加起来

    //区间查询
    void  ask_all(int k)
    {
        if(segTree[k].l>=x&&segTree[k].r<=y)
        {
            ans+=segTree[k].val;
            return;
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)ask_all(k*2);//这两行容易出错
        if(y>m)ask_all(k*2+1); 
    }

    (5)求区间最小值 建树过程

    //线段树查询区间最小值
    void build(int root,int l,int r)
    {
        if(segTree[root].l==segTree[root].r)
        {
            scanf("%d",&segTree[root].val);
            return;
        }
        int m=(segTree[root].l+segTree[root].r)>>1;
        build(root*2,l,m);
        build(root*2+1,m+1,r);
        segTree[root].val=min(segTree[root*2].val,segTree[root*2+1].val);//val从存和改为存其区间的最小值
    }

    (6)求区间最小值

    //线段树查询区间最小值 
    int ask_minn(int k)
    {
        if(segTree[k].l==segTree[k].r)
        {
            return segTree[k].val;
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)ask_minn(k*2);
        if(y>m)ask_minn(k*2+1);
    }

    (7)更新结点 修改最小值

    //线段树最小值结点更新
    void change_point(int k)
    {
        if(segTree[k].l==segTree[k].r)
        {
            segTree[k].val=x;
            return;
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)change_point(k*2);
        else change_point(k*2+1);
        segTree[k].val=min(segTree[k*2].val,segTree[k*2+1].val);
     } 

    (8)懒标记下传

    //懒标记下传 
    void down(int k)
    {
        segTree[k*2].s+=segTree[k].s;
        segTree[k*2+1].s+=segTree[k].s;
        segTree[k*2].val=segTree[k].s*(segTree[k*2].r-segTree[k*2].l+1);
        segTree[k*2+1].val=segTree[k].s*(segTree[k*2+1].r-segTree[k*2+1].l+1);
        segTree[k].s=0;
    }

    (9)线段树区间更新‘

    //线段树区间更新
    void change_sed(int k)
    {
        if(segTree[k].l>=x&&segTree[k].r<=y)
        {
            segTree[k].val+=x;
            segTree[k].s=x;
            return;
        }
        if(segTree[k].s)down(k);
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)change_sed(k*2);
        else change_sed(k*2+1);
    }

    四、线段树练习

    (1)http://codevs.cn/problem/1080/

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=100001;
    struct segTreenode
    {
        int l,r,val,s;
    }segTree[maxn*4];
    int n,m,od,x,y,pos,add,ans;
    inline void build(int root,int l,int r)
    {
        segTree[root].l=l;segTree[root].r=r;
        if(l==r)
        {
            scanf("%d",&segTree[root].val);
            return;
        }
        int m=(l+r)>>1;
        build(root*2,l,m);
        build(root*2+1,m+1,r);
        segTree[root].val=segTree[root*2].val+segTree[root*2+1].val;
    }
    inline void change_point(int k)
    {
        if(segTree[k].l==segTree[k].r)
        {
            segTree[k].val+=add;
            return;
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(pos<=m)change_point(k*2);
        else change_point(k*2+1);
        segTree[k].val=segTree[k*2].val+segTree[k*2+1].val;
    }
    inline void ask_sed(int k)
    {
        if(segTree[k].l>=x&&segTree[k].r<=y)
        {
            ans+=segTree[k].val;
            return;
        }
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)ask_sed(k*2);
        if(y>m)ask_sed(k*2+1);
    }
    int main()
    {
        scanf("%d",&n);
        build(1,1,n);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            ans=0;
            scanf("%d",&od);
            if(od==1)
            {
                scanf("%d%d",&pos,&add);
                change_point(1);
            }
          if(od==2)
            {
                scanf("%d%d",&x,&y);
                ask_sed(1);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    View Code

    (2)http://codevs.cn/problem/1081/

     #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=100001;
    struct segTreenote
    {
        int l,r,val,s;
    }segTree[maxn*4];
    int n,q,od,pos,x,y,z;
    inline void build(int root,int l,int r)
    {
        segTree[root].l=l;segTree[root].r=r;
        if(l==r)
        {
            scanf("%d",&segTree[root].val);
            return;
        }
        int m=(l+r)>>1;
        build(root*2,l,m);
        build(root*2+1,m+1,r);
        segTree[root].val=segTree[root*2].val+segTree[root*2+1].val;
    }
    inline void down(int k)
    {
        segTree[k*2].s+=segTree[k].s;
        segTree[k*2+1].s+=segTree[k].s;
        segTree[k*2].val+=segTree[k].s*(segTree[k*2].r-segTree[k*2].l+1);//.+
        segTree[k*2+1].val+=segTree[k].s*(segTree[k*2+1].r-segTree[k*2+1].l+1);
        segTree[k].s=0;
    }
    inline void add(int k)
    {
        if(segTree[k].l>=x&&segTree[k].r<=y)
        {
            segTree[k].val+=(segTree[k].r-segTree[k].l+1)*z;
            segTree[k].s+=z;
            return;
        }
        if(segTree[k].s)down(k);
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(x<=m)add(k*2);
        if(y>m) add(k*2+1);//
        segTree[k].val=segTree[k*2].val+segTree[k*2+1].val;
    }
    inline int ask(int k)
    {
        if(segTree[k].l==segTree[k].r)
        {
            return segTree[k].val;
        }
        if(segTree[k].s)down(k);
        int m=(segTree[k].l+segTree[k].r)>>1;
        if(pos<=m)ask(k*2);
        else ask(k*2+1);
    }
    int main()
    {
        scanf("%d",&n);
        build(1,1,n);
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d",&od);
            if(od==1)
            {
                scanf("%d%d%d",&x,&y,&z);
                add(1);
            }
            if(od==2)
            {
                scanf("%d",&pos);
                printf("%d
    ",ask(1));
            }
        }
        return 0;
     } 
    View Code

    呼~整理完了

  • 相关阅读:
    【bzoj1191】 HNOI2006—超级英雄Hero
    【poj3020】 Antenna Placement
    【poj1274】 The Perfect Stall
    【poj2724】 Purifying Machine
    【poj2226】 Muddy Fields
    【codevs1257】 打砖块
    【poj2186】 Popular Cows
    【poj1236】 Network of Schools
    【poj1144】 Network
    【poj3177】 Redundant Paths
  • 原文地址:https://www.cnblogs.com/zzyh/p/6798733.html
Copyright © 2020-2023  润新知