学习线段树

线段树的建树

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

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;
}

 

posted @ 2019-08-02 18:36  阿斯水生产线  阅读(143)  评论(0编辑  收藏  举报