题解:二维线段树+标记永久化。
因为是二维的所以在标记下传和信息上传的方面容易出现混乱,那么针对标记下传的问题我们考虑标记永久化,对于信息上传问题我们考虑信息不上传。
我们可以维护两颗二维线段树,一颗用来存储最大值,一颗用来维护标记。
因为高度是严格递增的所以对于一个确定的区域,有用的一定是当前区域的最大值,那么我们可以考虑用最大值+h来更新当前区域的答案,因为对于这个区域来说他的值一定会对从跟到当前的点的路径上的值产生影响,我们是不信息上传的,所以需要在更新当前区域的同时更新路径上的答案。
然后是标记永久化的问题。可以这么考虑,我们的标记是精确覆盖所属区域的,与普通线段树相比区别在于路径上的标记不会下方,但是对于一个区域对他有影响的标记无非就是跟到当前点路径上的所有标记,所以在计算答案的时候不能只考虑最大值线段树的答案,还应该考虑标记的答案。
注意这道题的内存有点卡,刚开始MLE了。。。。
#include
#include
#include
#include
using namespace std;
int m,n,t,w,s,d,x,y,ans,ansx;
struct segy{
int maxn[3003],mark[3003];
void change(int now,int l,int r,int ll,int rr,int val)
{
maxn[now]=max(maxn[now],val);
if (l>=ll&&r<=rr){
mark[now]=max(mark[now],val);
return;
}
int mid=(l+r)/2;
if (ll<=mid) change(now<<1,l,mid,ll,rr,val);
if (rr>mid) change(now<<1|1,mid+1,r,ll,rr,val);
}
int query(int now,int l,int r,int ll,int rr)
{
if (l>=ll&&r<=rr) return maxn[now];
int mid=(l+r)/2; int ans=mark[now];
if (ll<=mid) ans=max(ans,query(now<<1,l,mid,ll,rr));
if (rr>mid) ans=max(ans,query(now<<1|1,mid+1,r,ll,rr));
return ans;
}
};
struct segx{
segy maxn[3003],mark[3003];
void change(int now,int l,int r,int ll,int rr,int y,int y1,int val)
{
maxn[now].change(1,1,m,y,y1,val);
if (l>=ll&&r<=rr) {
mark[now].change(1,1,m,y,y1,val);
return;
}
int mid=(l+r)/2;
if (ll<=mid) change(now<<1,l,mid,ll,rr,y,y1,val);
if (rr>mid) change(now<<1|1,mid+1,r,ll,rr,y,y1,val);
}
int query(int now,int l,int r,int ll,int rr,int y,int y1)
{
if (l>=ll&&r<=rr) return maxn[now].query(1,1,m,y,y1);
int mid=(l+r)/2; int ans=mark[now].query(1,1,m,y,y1);
if (ll<=mid) ans=max(ans,query(now<<1,l,mid,ll,rr,y,y1));
if (rr>mid) ans=max(ans,query(now<<1|1,mid+1,r,ll,rr,y,y1));
return ans;
}
}T;
int main()
{
scanf("%d%d%d",&n,&m,&t);
for (int i=1;i<=t;i++)
{
scanf("%d%d%d%d%d",&d,&w,&s,&x,&y); x++; y++;
int x1=x+d-1; int y1=y+w-1; ans=0;
int t=T.query(1,1,n,x,x1,y,y1);
T.change(1,1,n,x,x1,y,y1,s+t);
}
printf("%d\n",T.query(1,1,n,1,n,1,m));
}