建立线段树,单点更新,单点查询,区间查询模板
const int maxn=200005;
int maxv[maxn<<2],w[maxn];//一般开4倍大小
void build(int id,int l,int r){
if(l==r){
maxv[id]=w[l];
return;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
maxv[id]=max(maxv[id<<1],maxv[id<<1|1]);
}
void update(int id,int l,int r,int x,int d){
if(l==r){
maxv[id]=d;
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(id<<1,l,mid,x,d);
else update(id<<1|1,mid+1,r,x,d);
maxv[id]=max(maxv[id<<1],maxv[id<<1|1]);
}
int query(int id,int a,int b,int l,int r){
if(a<=l&&r<=b)return maxv[id];
int ans=0;
int mid=(l+r)>>1;
if(a<=mid)ans=query(id<<1,a,b,l,mid);//在左区间还有一部分值
if(b>mid)ans=max(query(id<<1|1,a,b,mid+1,r),ans);//在右区间还有一部分值
return ans;
}
int simplequery(int id,int l,int r,int a){
if(l==r){
return maxv[id];
}
int mid=(l+r)>>1;
if(a<=mid)return simplequery(id<<1,l,mid,a);
else return simplequery(id<<1|1,mid+1,r,a);
}
lazy标记:区间更新,区间查询模板
对于区间更新,如果我们用朴素的方法对这个区间的每个节点都更新一次的话,O(logn)的更新时间就会变成O(nlogn),并且对于有些内容我们根本不需要查询,但是却遍历了。那么有没有什么快捷的方法呢?
对于每个要更新的区间的最大父区间增加一个lazy标记,标记这个区间会增加这个数(比如在一个l=1,r=10的区间对于a=4,b=7的区间进行增加1的操作,那么我们就会分别在[4,5]和[]的lazy[id]上增加1,并且把tree[id]加上这个区间长度乘以这个值,这样用于表示在我当前这个节点的左右节点中,还有没有增加的值)。这样的话 我们每次进行更新的遍历的层次就大大减小了,并且对于不需要遍历的层次也不需要进行更新,而如果我们需要对单点进行查询的时候,我们就可以把这个lazy数组进行下放操作。
const int maxn=100005;
long long tree[maxn<<2],lazy[maxn<<2];//lazy数组和线段树数组
void pushdown(int id,int l,int r){//进行下放操作,即将左右儿子节点的值增加当前lazy[id]*区间长度的值,并将当前的lazy标记清空为0
lazy[id<<1]+=lazy[id];
lazy[id<<1|1]+=lazy[id];
int mid=(l+r)>>1;
tree[id<<1]+=(mid-l+1)*lazy[id];
tree[id<<1|1]+=(r-mid)*lazy[id];
lazy[id]=0;
}
void update(int id,int l,int r,int x,int y,int d){
if(x<=l&&r<=y){//对于要更新的最大区间,进行lazy标记的增加和当前区间线段树值得增加
tree[id]+=(r-l+1)*d;
lazy[id]+=d;
return;
}
//因为后面还要进行左右节点求和得操作,所以我们要将当前节点的lazy标记进行下放
pushdown(id,l,r);
int mid=(l+r)>>1;
if(x<=mid)update(id<<1,l,mid,x,y,d);
if(y>mid)update(id<<1|1,mid+1,r,x,y,d);
tree[id]=tree[id<<1|1]+tree[id<<1];//对左右节点进行求和
}
long long query(int id,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tree[id];
}
//因为要查询当前节点的左右节点,所以要将当前节点的lazy数组进行下放
pushdown(id,l,r);
long long ans=0;
int mid=(l+r)>>1;
if(x<=mid)ans=query(id<<1,l,mid,x,y);
if(y>mid)ans+=query(id<<1|1,mid+1,r,x,y);
return ans;
}