线段树(成段更新)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/peter_xiazhen/article/details/82633406