get了新的标记永久化技能~
这题要求询问max和覆盖,因为是线段树套线段树,所以内外都不可以标记下传
这种标记永久化的套路是维护两个标记:$mx,all$,$mx$表示这个子树内的真最大值,$all$表示整个子树曾经被覆盖过这样的最大值
修改:更新经过节点的$mx$和覆盖区间节点的$all$
查询:统计经过节点的$all$和覆盖区间节点的$mx$
然后就不用下传标记了,还有写成struct会方便许多
类似地,区间加的标记永久化的两个标记是【子树和(假)】还有【子树增值】,【子树和(假)】+【子树增值】=【子树和(真)】
#include<stdio.h>
int n,m;
int max(int a,int b){return a>b?a:b;}
struct iseg{
int mx[3010],al[3010];
int query(int L,int R,int l,int r,int x){
if(L<=l&&r<=R)return mx[x];
int ans=al[x],mid=(l+r)>>1;
if(L<=mid)ans=max(ans,query(L,R,l,mid,x<<1));
if(mid<R)ans=max(ans,query(L,R,mid+1,r,x<<1|1));
return ans;
}
void modify(int L,int R,int v,int l,int r,int x){
mx[x]=max(mx[x],v);
if(L<=l&&r<=R){
al[x]=max(al[x],v);
return;
}
int mid=(l+r)>>1;
if(L<=mid)modify(L,R,v,l,mid,x<<1);
if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
}
};
struct oseg{
iseg mx[3010],al[3010];
int query(int L,int R,int Li,int Ri,int l,int r,int x){
if(L<=l&&r<=R)return mx[x].query(Li,Ri,1,m,1);
int ans=al[x].query(Li,Ri,1,m,1),mid=(l+r)>>1;
if(L<=mid)ans=max(ans,query(L,R,Li,Ri,l,mid,x<<1));
if(mid<R)ans=max(ans,query(L,R,Li,Ri,mid+1,r,x<<1|1));
return ans;
}
void modify(int L,int R,int Li,int Ri,int v,int l,int r,int x){
mx[x].modify(Li,Ri,v,1,m,1);
if(L<=l&&r<=R)return al[x].modify(Li,Ri,v,1,m,1);
int mid=(l+r)>>1;
if(L<=mid)modify(L,R,Li,Ri,v,l,mid,x<<1);
if(mid<R)modify(L,R,Li,Ri,v,mid+1,r,x<<1|1);
}
}t;
int main(){
int q,d,s,w,x,y;
scanf("%d%d%d",&n,&m,&q);
while(q--){
scanf("%d%d%d%d%d",&d,&s,&w,&x,&y);
t.modify(x+1,x+d,y+1,y+s,t.query(x+1,x+d,y+1,y+s,1,n,1)+w,1,n,1);
}
printf("%d",t.query(1,n,1,m,1,n,1));
}