线段树
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。
建树
int a[maxn]; //题目给出的数组
struct node //线段树
{
int l,r,sum,lazy;
}t[maxn*4];
void build(int l,int r,int k) //第k个节点,左儿子l,右儿子r
{
int mid = (l+r)/2;
t[k].l = l,t[k].r = r;
if(l == r)
{
t[k].sum = a[l];
return;
}
build(l,mid,k*2);
build(mid+1,r,k*2+1);
t[k].sum = t[k*2].sum + t[k*2+1].sum;
}
区间更新
void pushdown(int k) //把lazy值传递下去
{
if(t[k].lazy)
{
t[k*2].lazy += t[k].lazy;
t[k*2+1].lazy += t[k].lazy;
t[k*2].sum += t[k].lazy*(t[k*2].r - t[k*2].l + 1);
t[k*2+1].sum += t[k].lazy*(t[k*2+1].r - t[k*2+1].l + 1);
t[k].lazy = 0;
}
}
void update(int k,int l,int r,int x) //[l,r]区间加上x
{
if(l <= t[k].l && t[k].r <= r)
{
t[k].lazy += x;
t[k].sum += x * (t[k].r - t[k].l + 1);
return;
}
pushdown(k);
if(t[k*2].r >= l) update(k*2,l,r,x);
if(t[k*2+1].l <= r) update(k*2+1,l,r,x);
t[k].sum = t[k*2].sum + t[k*2+1].sum;
}
区间查询
int query(int k,int l,int r) //求[l,r]的和
{
if(l <= t[k].l && t[k].r <= r) return t[k].sum;
int res = 0;
pushdown(k);
if(t[k*2].r >= l) res += query(k*2,l,r);
if(t[k*2+1].l <= r) res += query(k*2+1,l,r);
return res;
}
区间赋值
有些时候需要把区间整体赋为某个值,我们可以利用lazy保存区间真正的值,然后至上而下更新,把+=改为=
void pushdown(int k)
{
if(t[k].lazy != -1)
{
t[k*2].lazy = t[k].lazy;
t[k*2+1].lazy = t[k].lazy;
t[k*2].sum = t[k].lazy*(t[k*2].r - t[k*2].l + 1);
t[k*2+1].sum = t[k].lazy*(t[k*2+1].r - t[k*2+1].l + 1);
t[k].lazy = -1;
}
}
void update(int k,int l,int r,int x)
{
if(l > r) return;
if(l <= t[k].l && t[k].r <= r)
{
t[k].sum = x*(t[k].r-t[k].l+1);
t[k].lazy = x;
return;
}
pushdown(k);
if(t[k*2].r >= l) update(k*2,l,r,x);
if(t[k*2+1].l <= r) update(k*2+1,l,r,x);
pushup(k);
}
模板
struct tree_node
{
int l,r,sum,lazy;
};
struct segtree
{
tree_node t[maxn*4];
void pushup(int k)
{
t[k].sum = (t[k*2].sum+t[k*2+1].sum)%M;
}
void pushdown(int k)
{
if(t[k].lazy)
{
t[k*2].lazy += t[k].lazy;
t[k*2+1].lazy += t[k].lazy;
t[k*2].sum += t[k].lazy*(t[k*2].r - t[k*2].l + 1);
t[k*2+1].sum += t[k].lazy*(t[k*2+1].r - t[k*2+1].l + 1);
t[k].lazy = 0;
}
}
void build(int k,int l,int r)
{
t[k].l = l,t[k].r = r;
if(l == r)
{
t[k].sum = 0; //初始值
return;
}
int mid = (l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
pushup(k);
}
void update(int k,int l,int r,int x)
{
if(l > r) return;
if(l <= t[k].l && t[k].r <= r)
{
t[k].sum = (t[k].sum + x*(t[k].r-t[k].l+1))%M;
t[k].lazy = (t[k].lazy + x)%M;
return;
}
pushdown(k);
if(t[k*2].r >= l) update(k*2,l,r,x);
if(t[k*2+1].l <= r) update(k*2+1,l,r,x);
pushup(k);
}
int query(int k,int l,int r)
{
if(l > r) return 0;
if(l <= t[k].l && t[k].r <= r)
{
return t[k].sum;
}
int res = 0;
pushdown(k);
if(t[k*2].r >= l) res = (res + query(k*2,l,r))%M;
if(t[k*2+1].l <= r) res = (res + query(k*2+1,l,r))%M;
return res;
}
}st;
参考博客:
https://www.cnblogs.com/xenny/p/9801703.html
https://blog.csdn.net/whereisherofrom/article/details/78969718