码迷,mamicode.com
首页 > 其他好文 > 详细

线段树

时间:2018-09-16 21:07:30      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:build   编号   这一   递归   建立   code   为什么   数组   sum   

一般先建立结构体,要开4倍,还有a数组,存一开始的数据

struct tree
{
    int l,r,sum;
}tr[N<<2];
int a[N];

建立一棵树

void built_tree(int x,int y,int i)
{
    tr[i].l =x;
    tr[i].r =y;
    if(x==y) tr[i].sum =a[x];
    else
    {
        int mid=(x+y)>>1;
        built_tree(x,mid,i<<1);//左树 
        built_tree(mid+1,y,i<<1|1);//右树 
        tr[i].sum =tr[i<<1].sum +tr[i<<1|1].sum; //和递归返回
    }
}

修改点的值,和查询

void update_tree(int q,int val,int i)
{
    if(tr[i].l ==q && tr[i].r ==q)
    tr[i].sum +=val;
    else
    {
        int mid=(tr[i].l+tr[i].r)>>1;
        if(q<=mid)
        update_tree(q,val,i<<1);
        else
        update_tree(q,val,i<<1|1);
        tr[i].sum =tr[i<<1].sum +tr[i<<1|1].sum; 
    }
}
int query_tree(int x,int y,int i)
{
    if(tr[i].l >=x&&tr[i].r <=y) return tr[i].sum ;
    else
    {
        int mid=(tr[i].l +tr[i].r )>>1;
        if(x>mid)
        return query_tree(x,y,i<<1|1);
        else if(y<=mid)
        return query_tree(x,y,i<<1);
        else
        return query_tree(x,y,i<<1)+query_tree(x,y,i<<1|1); 
    }
}

修改区间的值,查询

//重点详解:
//void pushdown(int);//下放惰性标记
//此处标记指的是惰性标记,实际上是让子节点暂时处于
//不更新状态等到用到的时候在做更新而区间加时要把和
//那个区间有关的区间全部价值,不然不配合输出
//超时了就要优化。
//你想啊,虽然x~y区间要增加一个值,难道这个区间就一
//定要用吗?
//如果区间值增加了但后来没有询问,我们一开始为什么
//要增加呢?
//正如背古文,如果考试不考,我们为什么要背呢?
//所以lazy思想就怎么产生了。
//lazy,就是懒嘛,就是先不被古文,等到考试要考了再
//去背嘛;
//先不增加区间,等到询问时在去增加嘛;
//我们可以搞一个add数组,专门把编号为num的区间要加
//的值记录下来
//如果要用了,再给线段树num加上v[num]的值,再把
//add[num]
//传给v[num*2]和v[num*2+1];然后v[num]清零
//“如果要用了”这一步用一个clean函数实现

//void buildtree(int,int,int);//构造线段树

//void update_tree(int,int,int,long long);//区间修改
//1,起始区间,终止区间,修改值

//long long query(int,int,int);//区间查询
//1,区间起始值,区间终止值

ll add[N<<2];//存惰性标记,也要四倍
void pushdown(int i)//下放惰性标记 
{
    ll lc=i<<1,rc=i<<1|1;
    tr[lc].sum +=(tr[lc].r -tr[lc].l +1)*add[i];
    tr[rc].sum +=(tr[rc].r -tr[rc].l +1 )*add[i];
    add[lc]+=add[i];
    add[rc]+=add[i];
    add[i]=0;
}
void update_tree(ll x,ll y,ll k,int i)
{
    ll lc=i<<1;
    ll rc=i<<1|1;
    if(tr[i].l>y||tr[i].r<x) return; //如果不属于,则返回
    if(x <= tr[i].l &&tr[i].r <=y)
    {
        tr[i].sum+=(tr[i].r -tr[i].l +1)*k;//加至此处不继续往下加 
        add[i]+=k;//存惰性标记 
    }else
    {
        if(add[i])
            pushdown(i);
        update_tree(x,y,k,lc);
        update_tree(x,y,k,rc);
        tr[i].sum =tr[lc].sum+tr[rc].sum; 
    } //查找 
}

ll query(ll x,ll y,int i)
{
    ll lc=i<<1,rc=i<<1|1;
    if(x <= tr[i].l && tr[i].r <= y) return tr[i].sum;
    if(x > tr[i].r|| y < tr[i].l) return 0;
    if(add[i])
        pushdown(i);
    return query(x,y,lc)+query(x,y,rc);
}

线段树

标签:build   编号   这一   递归   建立   code   为什么   数组   sum   

原文地址:https://www.cnblogs.com/wzl19981116/p/9657063.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!