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

    线段树的建树

    建树的写法根据题目要求来写,总体差距不大,但是要真正理解线段树才能写对

    struct SegmentTree
    {
        int l,r;  //l代表t[p]的左点
        int dat;    //等等 
    }t[size*4];
    void build(int p,int l,int r)
    {
        t[p].l=l,t[p].r=r;
        if(l==r) { t[p].dat=a[l] ;return ;}
        int mid=(l+r)/2;
        build(p*2,l,mid);        //从根节点寻找到叶节点
        build(p*2+1,mid+1,r);
        //这里是根据区间最大值为例来建树的
        t[p].dat=max(t[p*2].dat,t[p*2+1].dat);   //从叶节点到根节点更新数
    }

    线段树的单点修改

    单点修改没什么特别之处

    void change(int p,int x,int v)
    {
        if(t[p].l==t[p].r){t[p].dat=v;return;}      
        int mid=(t[p].l+t[p].r)/2;
        if(x<=mid) change(p*2,x,v); 
        else change(p*2+1,x,v);
        t[p].dat=max(t[p*2].dat,t[p*2+1].dat);      //从下往上更新信息
    }

    线段树的区间查询

    int ask(int p,int l,int r)
    {
        if(l<=t[p].l && r>=t[p].r) return t[p].dat;     //这里是包含关系,不理解的话可能会擅自改成等于
        int mid = (t[p].l + t[p].r)/2;
        int val=-(1<<30);    //负无穷大
        if(l<=mid) val=max(val,ask(p*2,1,r));
        if(r>mid)  val=max(val,ask(p*2+1,1,r));
        return val;
    }

    延迟标记 (线段树的特色)

    如果题目要求区间修改而不是单点修改,如果当你将这个区间每个都单点修改,时间会很复杂,所以用到延时标记。

    如果把区间里每个都单点修改,当在后面查询的时候有些只会用到某些根节点,而那些叶节点就白白更新了,浪费了时间。所以可以修改的时候标记,后面查询的时候在进行修改。

    POJ 3468

    void build(ll p,ll l,ll r)
    {
        l(p) = l,r(p)=r;
        if(l == r) {sum(p)=a[l] ;return ;}
        ll mid=(l+r)/2;
        build(p*2, l,mid);
        build(p*2+1 , mid+1,r);
        sum(p)+=sum(p*2)+sum(p*2+1);
    }
    void spread(ll p)
    {
        //cout<<p<<" "<<add(p)<<endl;
        if(add(p))
        {
            sum(p*2)+=add(p) * (r(p*2)-l(p*2)+1);
            sum(p*2+1)+= add(p) * (r(p*2+1)-l(p*2+1)+1);
            add(p*2)+=add(p);
            add(p*2+1)+=add(p);
            add(p)=0;
        }
    }
    void change(ll p,ll l,ll r,ll d )
    {
        if(l<=l(p) && r>=r(p))
        {
            sum(p)+=(ll  )d * (r(p)-l(p)+1);
            add(p) +=d;
            return ;
        }
        spread(p);
        ll mid = (l(p)+r(p))/2;
        if(l<=mid) change(p*2 , l, r, d);
        if(r>mid) change(p*2+1,l,r,d);
        sum(p) = sum(p*2)+sum(p*2+1);
    }
    ll ask(ll p,ll l,ll r)
    {
        cout<<p<<" ..."<<endl;
        if(l<=l(p) && r>=r(p) ) return sum(p);
        spread(p);
        ll mid = (l(p)+r(p))/2;
        ll val=0;
        if(l<=mid) val+=ask(p*2,l,r);
        if(r>mid) val+=ask(p*2+1,l,r);
        return val;
    }
  • 相关阅读:
    java运算符
    Java中的变量与常量
    java 的数据类型
    Windows Server 2012 R2上安装.Net4.6.1出错
    数据库面试基础知识整理
    C语言面试程序阅读整理
    C语言面试基础知识整理
    Android Studio工程项目打包成SDK(jar或aar格式)
    Android Studio 添加引用Module项目
    Android Studio打包SDK后,为什么没有bundles文件夹?
  • 原文地址:https://www.cnblogs.com/jrfr/p/11290565.html
Copyright © 2011-2022 走看看