[模板]-线段树-区间修改 + 区间查询
2017-09-03 22:05
405 查看
问题描述:
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
代码:
单点修改函数:
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
代码:
long long st[100000 << 2],lazy[100000 << 2];//数据最多10w个,于是储存线段树的数组开4倍即40w,lazy为标记数组 long long a[100000]; void PushUp(int node)//更新结点信息,这里的功能是求和,node为结点编号 { st[node] = st[node << 1] + st[(node << 1) | 1];//左儿子加右儿子 } void BuildTree(int node,int l,int r)//建树,node为节点编号,其代表着区间[l,r] { if(l == r)//边界,区间内只有一个元素 { st[node] = a[l];//直接赋值 return; } int mid = (l + r) / 2;//二分,注意位运算符号的方向!!! BuildTree(node << 1,l,mid);//左儿子 BuildTree(node << 1 | 1,mid + 1,r);//右儿子 PushUp(node);//现在得到了左儿子和右儿子的值,由它们得到父亲node的值 } void PushDown(int node,int ln,int rn)//下推标记的函数,ln为左儿子中元素的个数,rn为右儿子中元素的个数 { if(lazy[node])//如果该结点带着标记 { //下推标记 lazy[node << 1] += lazy[node];//左儿子 lazy[node << 1 | 1] += lazy[node];//右儿子 //修改儿子结点的值 st[node << 1] += ln * lazy[node]; st[node << 1 | 1] += rn * lazy[node]; lazy[node] = 0;//清除node结点的标记 } } void UpDate(int node,int l,int r,int a,int b,int c)//区间修改,[a,b]内的元素加c { if(a <= l && r <= b)//如果当前区间在区间[a,b]内 { st[node] += c * (r - l + 1);//更新当前结点,向上保持正确 lazy[node] += c;//打上标记,表示当前区间的st正确,儿子区间的st仍需要根据lazy的值来调整 return; } int mid = (l + r) / 2;//二分 PushDown(node,mid - l + 1,r - mid);//下推标记 if(a <= mid)//如果左儿子代表的区间[l,mid]与[a,b]有重叠 UpDate(node << 1,l,mid,a,b,c);//递归求解 if(b > mid)//如果右儿子代表的区间[mid + 1,r]与[a,b]有重叠 UpDate(node << 1 | 1,mid + 1,r,a,b,c);//递归求解 PushUp(node);//更新当前结点node } long long Query(int node,int l,int r,long long a,long long b)//区间查询,结点node所代表的区间为[l,r] { if(a <= l && r <= b)//如果在区间内 return st[node];//直接返回 long long mid = (l + r) / 2;//二分 PushDown(node,mid - l + 1,r - mid);//下推标记 long long ans = 0; if(a <= mid)//如果左儿子代表的区间[l,mid]与[a,b]有重叠 ans += Query(node << 1,l,mid,a,b); if(b > mid)//如果右儿子代表的区间[mid + 1,r]与[a,b]有重叠 ans += Query(node << 1 | 1,mid + 1,r,a,b); return ans; } int main() { int n,m; //输入 cin >> n >> m; for(int i = 1; i <= n; ++i) scanf("%lld",&a[i]); BuildTree(1,1,n);//先输入数列再建树!!! for(int i = 1; i <= m; ++i) { long long order,x,y,k; scanf("%lld",&order); if(order == 1) { scanf("%lld%lld%lld",&x,&y,&k); UpDate(1,1,n,x,y,k);//区间修改 } else { scanf("%lld%lld",&x,&y); printf("%lld\n",Query(1,1,n,x,y));//区间查询 } } return 0; }
单点修改函数:
void UpDate(int node,int l,int r,int L,int C)//单点更新,结点编号为node,所代表区间为[l,r],需要在a[L]上加C { if(l == r)//边界,如果区间内只有一个元素,那么它一定是a[L] { st[node] += C;//加上 return; } int mid = (l + r) / 2;//二分 if(L <= mid)//如果a[L]在左儿子代表的区间 UpDate(node << 1,l,mid,L,C); else UpDate(node << 1 | 1,mid + 1,r,L,C); PushUp(node);//向上更新(由左儿子和右儿子更新父亲) }
相关文章推荐
- P3372 【模板】线段树 1 区间查询与区间修改
- 模板(线段树 + 树状数组 + 区间修改 + 区间查询)eg:POJ 3468 - A Simple Problem with Integers
- 基本线段树模板(建树、点/区间修改、查询)
- 线段树模板(点修改 ,区间查询)
- HDU - 3577 Fast Arrangement (线段树区间修改及查询模板题)
- 【模板】线段树区间修改、区间求和、查询最值
- HDU1698 线段树入门之区间修改/查询(lazy标记法)
- HDU1166_敌兵布阵_线段树单点修改区间查询
- hdu 1754 线段树单点修改+区间查询
- hdu 1754 I Hate It【线段树】 区间修改,最值查询
- POJ_3468 A Simple Problem with Integers(线段树区间修改+附线段树模板)
- HDU1823 Luck and Love(二维线段树单点更新+区间查询+模板)
- hdu1754 I hate it线段树模板 区间最值查询
- Luck and Love(二维线段树单点更新+区间查询+模板)
- 【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询
- 【codevs1191】数轴染色 线段树 区间修改+固定区间查询
- 【codevs 1081】线段树练习2(单点查询+区间修改)
- hdu5493(线段树,离线操作,点修改,区间查询)
- POJ 2155 Matrix 二维线段树 区间修改 单点查询
- Tallest Cow POJ - 3263(线段树区间修改,单点查询)