【模板】线段树
线段树
前情提要
上周讲的线段树专题,没有太跟上,自己又把线段树的模板先敲了几遍,又增加了些许改进,用此博客以保存。
线段树模板
#include <iostream>
#include <cstdio>
#include <cmath>
#define N 200000
using namespace std;
//@start: 2020-03-17 21:43:16
//@end: 2020-03-19 22:22:10
/**
* 线段树模板v2.0
* 更新要点:
* 1. 代码简约化
* 2. 增加代码注释的详细度
* 3. 增加较为完备的函数参数注释
**/
int num[N]; //存放数据
int T[N<<2]; //线段树
int lazy[N<<2]; //懒数组,用于区间更新
/*
参数说明:
t:要更新的根节点
*/
void push_up(int t)
{//向上更新
T[t]=T[t<<1]+T[t<<1|1];
}
/*
参数说明:
t:要更新的根节点
d:根节点所管辖的区间长度,r-l+1
*/
void push_down(int t,int d)
{//向下更新,即下推懒标记
if(lazy[t])
{//如果当前根节点存在懒标记
//先下发给左右子节点
lazy[t<<1] += lazy[t];
lazy[t<<1|1] += lazy[t];
//左右子节点数值加上懒标记乘以管辖区间长度
T[t<<1] += lazy[t]*(d-(d>>1));
T[t<<1|1] += lazy[t]*(d>>1);
//当前根节点懒标记归零
lazy[t]=0;
}
}
/*
参数说明:
l,r:建树左右边界
t:建树根节点
*/
void build(int l,int r,int t)
{//建树
if(l==r)
{//找到叶子节点
T[t]=num[l];//赋值
return ;
}
int mid=(l+r)>>1;//取中值
build(l,mid,t<<1);//左子树
build(mid+1,r,t<<1|1);//右子树
push_up(t);//建完向上更新
return ;
}
/*
参数说明:
p,v:要更新的位置,更新的值
l,r:根节点左右边界
t:根节点
*/
void update(int p,int v,int l,int r,int t)
{//单点更新
if(l==r)
{//找到叶子节点
T[t]=v;
return ;
}
int mid=(l+r)>>1;//取中值
//没找到叶子节点
if(p<=mid)//该点在左子区间
update(p,v,l,mid,t<<1);
else //该点在右子区间
update(p,v,mid+1,r,t<<1|1);
push_up(t);//找完需要向上更新
}
/*
参数说明:
L,R:待更新区间
l,r:根节点左右边界
t:根节点
*/
void update_qj(int L,int R,int v,int l,int r,int t)
{//区间更新
int d=r-l+1;//当前节点管辖长度
if(l==L&&r==R)
{//找到要更新的点或区间
//更新数据及懒标记
T[t]+=d*v;
lazy[t]+=v;
return ;
}
push_down(t,d);//在查询之前向下更新
int mid=(l+r)>>1;//取中值
if(R<=mid)//更新区间完全在左子区间内
update_qj(L,R,v,l,mid,t<<1);
else if(L>mid)//更新区间完全在右子区间内
update_qj(L,R,v,mid+1,r,t<<1|1);
else//更新区间横跨左右子区间
{//Tip!!!:记得把更新区间也要从mid处断开
update_qj(L,mid,v,l,mid,t<<1);
update_qj(mid+1,R,v,mid+1,r,t<<1|1);
}
push_up(t);
return ;
}
/*
参数说明:
L,R:待查询区间
l,r:根节点左右边界
t:根节点
*/
int query(int L,int R,int l,int r,int t)
{//查询
if(L==l&&R==r)//找到
return T[t];
push_down(t,r-l+1);
int mid=(l+r)>>1;//取中值
//加法的线段树查询写法
if(R<=mid)//查询区间完全在左子区间内
return query(L,R,l,mid,t<<1);
else if(L>mid)//查询区间完全在右子区间内
return query(L,R,mid+1,r,t<<1|1);
else//查询区间横跨左右子区间
return query(L,mid,l,mid,t<<1)+query(mid+1,R,mid+1,r,t<<1|1);
//Tip!!!:记得把更新区间也要从mid处断开
}
int main()
{
/**
* 1. 输入数据总数n
* 2. 输入所有数据
* 3. build建造
* 4. 根据题意操作
**/
return 0;
}
道生一,一生二,二生三,三生万物。

浙公网安备 33010602011771号