函数库 线段树lazy标记
如果在题目中使某个区间所有元素的对应值*x或+-x,直接用线段树对每个元素进行计算,时间复杂度升高为nlogn,而用lazy标记可以减小时间复杂度。
假设需要对某区间+num;
void pushup(int p) {//数值向上传递 dat[p]=dat[2*p]+dat[2*p+1]; } void pushdown(int p,int m) {//将lazy标记传递给左儿子和右儿子,同时初始化自己的lazy标记,这样在未来的运算中,减少所走步数。 if(add[p]) { add[p*2]+=add[p]; add[p*2+1]+=add[p]; dat[p*2]+=(m-(m/2))*add[p]; dat[p*2+1]+=(m/2)*add[p]; add[p]=0; } } void update(int x,int y,long long num,int l,int r,int p) {//更新每个节点的数值,与change函数类似,但是多了lazy标记的运算。 if(x<=l&&r<=y) { add[p]+=num; dat[p]+=num*(r-l+1); return ; } pushdown(p,r-l+1); int mid=(l+r)/2; if(x<=mid) update(x,y,num,l,mid,p*2); if(y>mid) update(x,y,num,mid+1,r,p*2+1); pushup(p); } void build(int p,int l,int r) { add[p]=0; if(l==r) {dat[p]=a[l];return;} int mid=(l+r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); dat[p]=dat[p*2]+dat[p*2+1]; } long long find(int p,int l,int r,int x,int y) {//计算区间和的时候,必须考虑到lazy标记的传递。 if((x<=l)&&(r<=y))return dat[p]; pushdown(p,r-l+1); int mid=(l+r)/2; if(mid>=y)return find(p*2,l,mid,x,y); if(mid<x)return find(p*2+1,mid+1,r,x,y); long long t=find(p*2,l,mid,x,y)+find(p*2+1,mid+1,r,x,y); return t; }