题目最多给到10万个操作,简单的线段树会超时,需要用到lazy标记。
在区间修改时,如果每次都更新到叶子节点会非常耗费时间,所以当某次更新的区间与当前更新的区间一致的话,则本次更新仅更新该节点,并将该节点的子节点用lazy标记, lazy标记意味着本节点已经更新过了,而本节点的子节点仍需根据标记信息进行更新。等到下次用到时再根据lazy标记的信息更新子节点,并将lazy标记下传,且取消该节点的标记。
定义线段树存储结构:
struct tree{
int l,r;
int lazy;
int val;
}a[maxn*4];
核心操作(标记下传):
void pushdown(int i) //下传lazy标记
{
if(a[i].lazy){
a[i<<1].lazy=a[i].lazy;
a[i<<1].val=a[i].lazy*(a[i<<1].r-a[i<<1].l+1);
a[i<<1|1].lazy=a[i].lazy;
a[i<<1|1].val=a[i].lazy*(a[i<<1|1].r-a[i<<1|1].l+1);
a[i].lazy=0;
}
}
hdu 1698:
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
struct tree{
int l,r;
int lazy;
int val;
}a[maxn*4];
void pushup(int i){ //回溯更新
a[i].val=a[i<<1].val+a[i<<1|1].val;
}
void pushdown(int i) //下传lazy标记
{
if(a[i].lazy){
a[i<<1].lazy=a[i].lazy;
a[i<<1].val=a[i].lazy*(a[i<<1].r-a[i<<1].l+1);
a[i<<1|1].lazy=a[i].lazy;
a[i<<1|1].val=a[i].lazy*(a[i<<1|1].r-a[i<<1|1].l+1);
a[i].lazy=0;
}
}
void build(int i,int l,int r)
{
a[i].l=l;
a[i].r=r;
a[i].val=0;
a[i].lazy=1;
if(l==r) a[i].val=1;
else{
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
pushup(i);
}
}
void update(int i,int l,int r,int type){
if(l<=a[i].l&&a[i].r<=r){
a[i].lazy=type;
a[i].val=type*(a[i].r-a[i].l+1);
}
else{
pushdown(i);
int mid=(a[i].l+a[i].r)>>1;
if(l<=mid) update(i<<1,l,r,type);
if(r>mid) update(i<<1|1,l,r,type);
pushup(i);
}
}
int main()
{
int i,j,n,m,t,x,y,z,ans=1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
scanf("%d",&m);
build(1,1,n);
for(i=0;i<m;i++){
scanf("%d %d %d",&x,&y,&z);
update(1,x,y,z);
}
printf("Case %d: The total value of the hook is %d.\n",ans,a[1].val);
ans++;
}
return 0;
}