void pushdown(int rt,int l,int r) //非永久性标记,向下递归
{
if(lazy[rt])
{
ll le = (r+l>>1)-l+1; //左子树长度
ll re = r-l+1-le; //右子树长度
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt]*le;
sum[rt<<1|1] += lazy[rt]*re;
lazy[rt] = 0; //清空
}
}
ll query(int l,int r,int rt,int ql,int qr) //查找函数(求和sum)
{
if(ql<=l&&qr>=r) return sum[rt];
else
{
push(rt,l,r); //我们要去处理它的儿子节点了,就需要把Lazy标记往下推了
int mid = l + r>>1; //这里说明一下:‘+’优先级比'>>'符号高
ll ret = 0;
if(ql<=mid) ret += query(l,mid,rt<<1,ql,qr);
if(qr>mid) ret += query(mid+1,r,rt<<1|1,ql,qr);
return ret;
}
}
void update(int l,int r,int rt,int ql,int qr,int v) //更新函数
{
if(ql<=l&&qr>=r) sum[rt] += (r-l+1)*v,lazy[rt] += v; //此处强调一定要对sum求和别忘记,不然更新父节点会少值
else
{
pushdown(rt,l,r); //说明这个根结点的范围有不在(ql, qr)范围内的,需要递归到下一层去寻找范围内的区间
int mid = l+r>>1;
if(ql<=mid) update(l,mid,rt<<1,ql,qr,v);
if(qr>mid) update(mid+1,r,rt<<1|1,ql,qr,v);
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
}
//标记永久化(永久化标记)
void push(int rt,int l,int r) //就是pushudown的作用
{
if(lazy[rt]==0)return;
ll le = (r+l>>1)-l+1;
ll re = r-l+1-le;
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt]*le;
sum[rt<<1|1] += lazy[rt]*re;
lazy[rt] = 0;
}
ll query(int l,int r,int rt,int ql,int qr)
{
if(ql<=l&&qr>=r) return sum[rt];
else
{
//push(rt,l,r);
int mid = l + r>>1;
ll ret = 1ll*(min(qr,r)-max(ql,l)+1) * lazy[rt];
if(ql<=mid) ret += query(l,mid,rt<<1,ql,qr);
if(qr>mid) ret += query(mid+1,r,rt<<1|1,ql,qr);
return ret;
}
}
void update(int l,int r,int rt,int ql,int qr,int v)
{
if(ql<=l&&qr>=r) sum[rt] += 1LL*(r-l+1)*v,lazy[rt] += v;
else
{
int mid = l+r>>1;
if(ql<=mid) update(l,mid,rt<<1,ql,qr,v);
if(qr>mid) update(mid+1,r,rt<<1|1,ql,qr,v);
sum[rt] = sum[rt<<1] + sum[rt<<1|1] + lazy[rt]*(r-l+1);
}
}