版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/peter_xiazhen/article/details/82633406
1、提出背景:给你N个点,执行M次操作,每次操作让你把[X,Y]区间里的元素都加Z。
2、为什么要进行成段更新?
答:如果不进行成段更新,那么在单点更新的基础上,我们是不是要把[X,Y]中的元素都进行单点更新,时间复杂度会相当的高!!!
3、成段更新在单点更新的基础上会有什么不同呢?
答:最大的不同在原来基础上增加了 lazy[ ](延迟数组)进行标记。我的理解是,当我们要对某个区间进行更新操作,那么我们只需要找到这个区间,对这个区间进行整体操作,不需要对该区间的子区间结点也进行更新操作,但是需要用lazy [ ] 数组存储这次的更新操作,以便下次需要对之后的子区间里的结点时,除了当次操作外,还要行事之前未进行的更新操作。((⊙﹏⊙),描述的可能不清楚)。举个简单的例子:我们要对[a,b]进行加c操作。那么从根节点[1,n]开始,若执行到p结点,他的区间刚好对应[a,b],这是我们可以一步更新区间整体。eg.tree[p] + = c * (r-l+1)。注意关键来了,如果此时按照常规的线段树进行change操作,这时候还应该更新p的子节点中的tree[ ]值(tree维护区间和)。而lazy [ ]思想恰恰暂时先不更新p的子节点中的tree [ ] 值,到此结束返回。直到下次需要用到p的子节点的值时采取更新。(lazy顾名思义了)。这样会避免许多无用操作,降低时间复杂度。
pushdown()操作:
void pushdown(int p,int len)
{
if (lazy[p]){
lazy[p<<1] = lazy[p]; // 向下传递之前未进行的更新操作
lazy[p<<1|1] = lazy[p];
tree[p<<1] = (len-(len>>1)) * lazy[p]; //不同的题目对应不同的操作,这里可以体会下
tree[p<<1|1] = (len>>1)*lazy[p];
lazy[p] = 0;
}
}
hdu 1698:
//线段树区间更新,加上延迟数组
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <string>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int tree[maxn<<2],a[maxn],lazy[maxn<<2];
int t,q,n;
void pushdown(int p,int len)
{
if (lazy[p]){
lazy[p<<1] = lazy[p];
lazy[p<<1|1] = lazy[p];
tree[p<<1] = (len-(len>>1)) * lazy[p]; //不同的题目对应不同的操作
tree[p<<1|1] = (len>>1)*lazy[p];
lazy[p] = 0;
}
}
void build(int p,int l,int r)
{
lazy[p] = 0;
if (l==r) {
tree[p]=a[l];
return ;
}
int mid = (l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
tree[p] = tree[p<<1] + tree[p<<1|1];
}
void change(int p,int l,int r,int x,int y,int num)
{
if (x<=l&&r<=y){
tree[p] = (r-l+1)*num;
lazy[p] = num;
return ; //把当前的结点更新完就不再往下继续更新了,等下次更新的操作.
}
pushdown(p,r-l+1);//向下更新。
int mid = (l+r)>>1;
//区间常规操作
if (y<=mid) {
change(p<<1,l,mid,x,y,num);
}
else if (x>mid){
change(p<<1|1,mid+1,r,x,y,num);
}
else{
change(p<<1,l,mid,x,mid,num);
change(p<<1|1,mid+1,r,mid+1,y,num);
}
tree[p] = tree[p<<1]+tree[p<<1|1];
}
int main()
{
scanf("%d",&t);
int kase = 1;
while(t--)
{
memset(a,0,sizeof(a));
memset(tree,0,sizeof(tree));
scanf("%d",&n);
for(int i=1;i<=n;i++) a[i]=1;
build(1,1,n);
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
change(1,1,n,x,y,z);
}
printf("Case %d: The total value of the hook is %d.\n",kase++,tree[1]);
}
return 0;
}