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)); }