线段树模板
题目传送门
经典的线段树问题,区间修改区间查询
这里需要用到一种方法:延迟标记(懒标记)
举个例子,我们想要让区间1-10的数加上20,但是来,我们以后可能压根都用不着这一区间,这样就造成了时间的极大浪费,这样的情况下,就想到了一个办法,如果更新到区间[1,5],因为区间[1,10],是包括区间[1,5]的,所以我们就可以开个数组add,假设区间1-5的编号是k,那么就使add[k]+=20;
下面就附上各部分实现的代码:
//建树操作
void built(ll k,ll l,ll r){
if(l==r){
sum[k]=a[l];
return ;
}
ll mid=l+r>>1;
built(k<<1,l,mid);//二进制,=k*2
built(k<<1|1,mid+1,r);//同上
sum[k]=sum[k<<1]+sum[k<<1|1];
}
下面是区间修改的操作
void modify(ll k,ll l,ll r,ll x,ll y,ll v){
if(x<=l&&y>=r) return Add(k,l,r,v);//如果区间已包括l,r,那就直接标记就好啦
ll mid=l+r>>1;
pushdown(k,l,r,mid);
if(x<=mid) modify(k*2,l,mid,x,y,v);
if(y>=mid+1) modify(k*2+1,mid+1,r,x,y,v);
sum[k]=sum[k*2]+sum[k*2+1];
}
add函数
void Add(ll k,ll l,ll r,ll v){
add[k]+=v;
sum[k]+=(r-l+1)*v;//别忘了把当前区间的值更改
return;
}
再下面就是最麻烦的区间修改了
ll query(ll k,ll l,ll r,ll x,ll y){
if(x<=l&&y>=r) return sum[k];
ll mid=l+r>>1;
ll res=0;
pushdown(k,l,r,mid);//标记下传
if(x<=mid) res+=query(k*2,l,mid,x,y);//包含左区间
if(y>=mid+1) res+=query(k*2+1,mid+1,r,x,y);//包含右区间
return res;
}
void pushdown(ll k,ll l,ll r,ll mid){//标记向下尅一层
if(add[k]==0) return;
Add(k<<1,l,mid,add[k]);
Add(k<<1|1,mid+1,r,add[k]);
add[k]=0;//别忘记把当层清零
}
到此搁笔吧,祝愿能进复赛啊