线段树是一种二叉搜索数,每一个节点都对应一定的区间,能够快速的对区间进行更新,时间复杂度比较小;
常运用于线段树的一个算法是lazy思想,lazy思想是说若更新的区间已经完全包含区间s,将s区间标记,暂不向下更新,若下一次的更新或
询问需要用的已经标记过的区间的子区间,再将标记过得区间进行向下更新,并且取消对区间s的标记,增加对区间两个左右子树的标记。若
一直未询问到,则不向下更新。通过这种方式可以达到节约时间的目的。
举例说明: 进行区间更新,并进行区间求和;
声明节点:
struct point
{
int l,r;
int x,add;//x为当前区间的总价值,add对应的是当前区间的值
bool is_updata;// 判断是否更新;
};
node tree[4*maxn];
//向上更新:
void updata_up(int k)
{
tree[k].x=tree[k<<1].x+tree[k<<1|1].x;
}
//向下更新
void updata_down(int k)
{
if(tree[k].is_updata)
{
tree[k<<1|1].x=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].add;
tree[k<<1].x=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].add;
tree[k<<1|1].add=tree[k<<1].add=tree[k].add;
tree[k<<1|1].is_updata=tree[k<<1].is_updata=true;
tree[k].is_updata=false;
}
}
//建立二叉树
void build(int l,int r,int k)
{
tree[k].l=l,tree[k].r=r;
tree[k].is_updata=false,tree[k].x=0;
tree[k].add=0;
if(l==r)
{
tree[k].x=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);//头节点为1;
build(mid+1,r,k<<1|1);
updata_up(k);
}
//进行区间更新
void updata(int l,int r,int x,int k)
{
if(tree[k].l>=l&&tree[k].r<=r)
{
tree[k].x=(tree[k].r-tree[k].l+1)*x;
tree[k].add=x;
if(r!=l) tree[k].is_updata=true;// 将区间标记,暂不向下更新
return;
}
updata_down(k);//判断节点k是否被标记过,若被标记过,则此时需要向下更新
if(tree[k<<1].r>=l) updata(l,r,x,k<<1);
if(tree[k<<1|1].l<=r) updata(l,r,x,k<<1|1);
updata_up(k);
}
最后直接输出tree[k].x即为所求;