首先是改进了上一段代码的表示方法,不将num节点所存储的区间端点放在结构体中,而是放在函数中作为参数传入,可以用macro简化代码。【代码中的大写字母L,R都代表num节点的左右端点,小写字母l,r代表查询或修改区间的左右端点】 其次是用pushDown函数和lazy标记实现了区间修改,因为区间修改没有必要在查询到它之前去向下传递,在修改时只需要检查当前num节点是否有lazy,如果有,pushDown之后看修改区间在什么位置对左右子树进行递归操作。查询和修改几乎完全一样。
#include <cstdio> #include <cstring> #define maxn 100000+10 #define lson L,mid,rt<<1 //左子树 左端点,右端点,编号 #define rson mid+1,R,rt<<1|1 #define root L,R,rt struct node{ int val, lazy; }T[maxn<<2]; void pushUp(int num){//num节点的左右子树都已经更新完毕了再pushUp更新num本身 T[num].val=T[num<<1].val+T[num<<1|1].val; } void pushDown(int L,int R,int num){ int mid=(L+R)>>1; T[num<<1].val=T[num].lazy*(mid-L+1); T[num<<1|1].val=T[num].lazy*(R-mid); T[num<<1].lazy=T[num].lazy; T[num<<1|1].lazy=T[num].lazy; T[num].lazy=0; } void build(int L,int R,int num){ if(L==R){ scanf("%d",&T[num].val); return; //如果数组s[i]是已经读入的数据的话 //T[num].val=s[L]; return; } int mid=(L+R)>>1; build(lson); build(rson); pushUp(num);//左右子树都计算完成了就可以把自己算出来啦 } void update(int l,int r,int v,int L,int R,int rt){ //在覆盖[L,R]的rt节点的[l,r]区间增加v if(l==L&&r==R){ T[rt].lazy=v; T[rt].val=v*(R-L+1); return; } int mid=(L+R)>>1; if(T[rt].lazy) pushDown(root); if(r<=mid) update(l,r,v,lson);//注意向下取整左取等右不取等 else if(l>mid) update(l,r,v,rson); else{ update(l,mid,v,lson); update(mid+1,r,v,rson); } pushUp(num); } int query(int l,int r,int L,int R,int rt){ if(l==L&&r==R) return T[rt].val; int mid=(L+R)>>1; if(T[rt].lazy) pushDown(root); if(r<=mid) return query(l,r,lson); else if(l>mid) return query(l,r,rson); return query(l,mid,lson)+query(mid+1,r,rson); } int main(){ int n,q; scanf("%d",&n); build(1,n,1);//从根节点开始建树 scanf("%d",&q); while(q--){ //应对多组查询 } return 0; }HDU 1166 单点修改,区间查询,用树状数组也可以实现 HDU 1754 查询区间最大值 HDU 1698 区间修改,区间查询,lazy思想 HDU 1394 求逆序数,也可以用树状数组,记录每个位置与左边的差 POJ 2777 位运算,区间修改
转载于:https://www.cnblogs.com/leotan0321/p/6081369.html