C - Just a Hook HDU - 1698(线段树+lazy标记+区间更新)

在这里插入图片描述
在这里插入图片描述
题意:给你n初始化数组全为1,然后给你m个询问,每个询问就是改区间[X,Y]所对应的值为Z;

这道题的主要难点在与push_down和lazy标记;其实我在学习线段树的时候也没太清楚这个lazy有什么用;但是现在明白了;
它是为了减少时间复杂度的;其实线段树的基本操就有:
1.建树;
2.单点更新;
3.区间的RMQ问题;
4.区间更新;
其实这些问题都是基于二叉树的后续遍历而引出来的;
懒惰标记有什么作用?
它可以如何提高效率?
1.作用:明显减少时间;
2.如何提高的呢?
我可以这样理解(其实lazy数组主要还是用于存倍数关系的):
在这里插入图片描述
如果下一次递归到标记的地方那么他就不用一直一直递归到叶结点了;因为平常写的都是递归到叶结点;
而当它递归到标记点时;那么就可以直接return了;这样就不用往下走了;而它的厉害之处就在于push_down函数;
这个还是是把lazy下放到左孩子+右孩子,同时通过它,对应的节点的左孩子+右孩子可以改变值,通过lazy的下放;
其实这里光解释肯定不行,因为必须要结合代码来理解它;
AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int Tree[maxn<<2],n,T,lazy[maxn<<2];
int ans;
void push_up(int root){//这里其实就是一个父节点存孩子的值
	  Tree[root]=Tree[root<<1]+Tree[(root<<1)|1];
}
void push_down(int root,int L ,int R){//下放
	 if (L>R) return ;
    if (lazy[root]==0)    return ;
	if(lazy[root]!=0){//如果被标记,那么就下放
		 lazy[root<<1]=lazy[root];//lazy和Tree是对应的关系,只不过lazy存的通常是倍数;
		 lazy[(root<<1)|1]=lazy[root];
		 int mid=(L+R)/2;
		 Tree[root<<1]=(mid-L+1)*lazy[root<<1];//这里用笔算一下就知道为什么了
		 Tree[(root<<1)|1]=(R-mid)*lazy[(root<<1)|1];
		 	 lazy[root]=0;//下放之后,取消标记
	}
}
void Build(int root,int L,int R){//建树L,R为系统区间
	  if(L==R){
	  	  Tree[root]=1;
	  	 // cout<<Tree[root]<<" ";
	  	  return ;
	  }else{
	  	 int mid=(L+R)/2;
	  	 Build(root<<1,L,mid);
	  	 Build((root<<1)|1,mid+1,R);
	  	 push_up(root);
	  }
}
void Query(int root ,int L,int R,int l,int r){
	  if(l>r||L>R)return;
	  if(l<=L&&R<=r){
	      ans+=Tree[root];return;
	  }
	    int mid=(L+R)/2;
	  if(l<=mid) Query(root<<1,L,mid,l,r);//这里的递归就很好了,因为解决了复杂的讨论问题直接,根据mid和l的大小来递归,注意这里的l,r值是没有变的,所以结束时室包含关系,其实就是l,r包含所递归到的系统区间
	  if(r>mid) Query((root<<1)|1,mid+1,R,l,r);
}
void updata(int root,int L,int R,int l,int r,int val){
	    if(l>r||L>R)return ;
	    if(l<=L&&R<=r){
	    	  Tree[root]=(R-L+1)*val;
	    	 // cout<<Tree[root]<<" ";
	    	 lazy[root]=val;//这里需要标记倍数,以便下放
	    	  return ;
		}
		int mid=(L+R)/2;
		push_down(root,L,R);//下放
		if(l<=mid)updata(root<<1,L,mid,l,r,val);//这里的递归和线段树区间求和Sum操作一个道理
	    if(r>mid)updata((root<<1)|1,mid+1,R,l,r,val);
		push_up(root);
}
int main(){
	scanf("%d",&T);
	int m,x,y,z;
	for(int i=1;i<=T;i++){
		ans=0;//注意每次更新一下值
		memset(lazy,0,sizeof(lazy));
		  scanf("%d",&n);
		  Build(1,1,n);
		  scanf("%d",&m);
		  while(m--){
		  	 scanf("%d %d %d",&x,&y,&z);
		  	 updata(1,1,n,x,y,z);
		  }
		  Query(1,1,n,1,n);
		  printf("Case %d: The total value of the hook is %d.\n",i,ans);
	}
	return 0;
} 

.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值