题意:给你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;
}
.