总结了一下线段树的基本运用和操作,也方便日后知识的梳理和Ctrl C+V提高AC率
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define N 100//N是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int sum[N*2];
int n;
int col[N<<2]
inline void pushup(int rt)//从其子节点更新当前节点
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
inline void build(int l,int r,int rt)//建树
{
if(l==r)
{
scanf("%d",&sum[rt]);
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
inline int query(int L,int R,int l,int r,int rt)//求区间[L,R]的和 ,也可以查询区间最值
{
if(L<=l&&R>=r)return sum[rt];//若要求的区间[L,R]包括递归到的区间[l,r]则加上该节点的值
int m=(l+r)>>1;
int ret=0;
if(L<=m)ret+=query(L,R,lson);//向右递归 ,查询区间最值就直接把+=改为max或者min就好
if(R>m)ret+=query(L,R,rson);//向左递归
return ret;
}
inline void update(int p,int add,int l,int r,int rt)//单点增减或改变
{
if(l==r)
{
sum[rt]+=add;//单点增减
//sum[rt]=add;单点更换
return;
}
int m=(l+r)>>1;
if(p<=m)update(p,add,lson);
else update(p,add,rson);
pushup(rt);//因为更新了子节点,自然要维护,所以父节点也要变
}
inline void pushdown(int rt,int m)//延迟更新 ,其实本质上不过是只更新父节点,然后有需要才更新子节点
{ //举个例子,有一家企业,政府要来检查某一个部门的总薪资,这个部门的领导为了增加腰包(贪腐),就多报了。
if(col[rt]) //至于下面一层层工人就打个标记,政府检查到哪个就给哪个把薪资加上,这样就可以最大限度增加腰包
{ //对于我们来说这么做线段树就可以只应付需要的部分,若是不用(政府不检查)就不用更新,就可以减小时间复杂度
col[rt<<1]=col[rt<<1|1]=col[rt];
sum[rt<<1]+=(m-(m>>1))*col[rt];
sum[rt<<1|1]+=(m>>1)*col[rt];
col[rt]=0;
}
}
void update(int L,int R,int c,int l,int r,int rt) //整个区间[l,r]增减c或者改变为c
{ //总体上和单点修改差不多,就多了要标记一下,和判断一下当前节点rt是否被标记
if (L<=l&&R>=r)
{
col[rt]=c;
sum[rt]=c*(r - l + 1);
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if (L<=m) update(L,R,c,lson);
if (R>m) update(L,R,c,rson);
pushup(rt);
}
inline int query(int L,int R,int l,int r,int rt) //延迟标记时的区间求和,其实就是多了个处理标记的~~~
{
if (L<=l&&R>=r) return sum[rt];
pushdown(rt,r-l+1);
int m=(l+r)>>1;
int ret=0;
if(L<=m)ret+=query(L,R,lson);
if(m<R)ret+=query(L,R,rson);
return ret;
}
int main()
{
}
延迟更新(或者说懒惰更新)是在要修改这个节点或查询这个节点时做的