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

    终于学完了线段树,没学之前觉得特牛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

    呼~整理完了

  • 相关阅读:
    Running ASP.NET Applications in Debian and Ubuntu using XSP and Mono
    .net extjs 封装
    ext direct spring
    install ubuntu tweak on ubuntu lts 10.04,this software is created by zhouding
    redis cookbook
    aptana eclipse plugin install on sts
    ubuntu open folderpath on terminal
    ubuntu install pae for the 32bit system 4g limited issue
    EXT Designer 正式版延长使用脚本
    用 Vagrant 快速建立開發環境
  • 原文地址:https://www.cnblogs.com/zzyh/p/6798733.html
Copyright © 2011-2022 走看看