BZOJ1513
我们经常提及的二维线段树有两种写法,一种是四分树,一种是树套树,写成四分树的都是神仙。
树套树写法还是比较好理解的,不过要是让自己硬套的话可能很不容易套出来的
这里的二维线段树,外层线段树是对方阵的正投影,而内层线段树是对方阵的侧投影
这里的内层线段树可以变换成一棵普通的带lazy tag的线段树,外层的应该很难吧
然后,介绍一下怎么写:
int D,S,N,ql,qr,qd,qu;
D是矩阵长,S是矩阵宽,N是修改(修改内嵌查询)的次数,然后ql,qr,qd,qu表示每一次修改区间的四个端点
我们看内层线段树,内层线段树其实就是维护了一个最值
struct segx { int v[3005],tag[3005]; void change(int k,int l,int r,int x,int y,int val) { v[k]=max(v[k],val); if(l==x&&y==r) {tag[k]=max(tag[k],val);return;} int mid=(l+r)>>1; if(x<=mid) change(k<<1,l,mid,x,min(mid,y),val); if(y>mid) change(k<<1|1,mid+1,r,max(x,mid+1),y,val); } int query(int k,int l,int r,int x,int y) { if(l==x&&y==r) return v[k]; int mid=(l+r)>>1,ans=tag[k]; if(x<=mid) ans=max(ans,query(k<<1,l,mid,x,min(mid,y))); if(y>mid) ans=max(ans,query(k<<1|1,mid+1,r,max(x,mid+1),y)); return ans;
如果不是追求极限的做法,直接这样就可以了了,没必要加上lazytag,因为那样应该不是题目重点(除非是出题人,有脑洞。。)
然后是外层线段树,这里的衔接还是比较自然地,不像别的树套树,可以这么形容一下,别的树套树衔接都是带锯齿的,这里是平滑的
struct segy { segx v[3005],tag[3005]; void change(int k,int l,int r,int x,int y,int val) { v[k].change(1,1,S,qd,qu,val); if(l==x&&y==r) {tag[k].change(1,1,S,qd,qu,val);return;} int mid=(l+r)>>1; if(x<=mid) change(k<<1,l,mid,x,min(mid,y),val); if(y>mid) change(k<<1|1,mid+1,r,max(x,mid+1),y,val); } int query(int k,int l,int r,int x,int y) { if(l==x&&y==r) return v[k].query(1,1,S,qd,qu); int mid=(l+r)>>1,ans=tag[k].query(1,1,S,qd,qu); if(x<=mid) ans=max(ans,query(k<<1,l,mid,x,min(mid,y))); if(y>mid) ans=max(ans,query(k<<1|1,mid+1,r,max(x,mid+1),y)); return ans; } }T;
我们可以看到内外还是比较协调统一的,最后给出完整实现:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int D,S,N,ql,qr,qd,qu; 5 long long read() 6 { 7 long long x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} 10 return x*f; 11 } 12 struct segx 13 { 14 int v[3005],tag[3005]; 15 void change(int k,int l,int r,int x,int y,int val) 16 { 17 v[k]=max(v[k],val); 18 if(l==x&&y==r) {tag[k]=max(tag[k],val);return;} 19 int mid=(l+r)>>1; 20 if(x<=mid) change(k<<1,l,mid,x,min(mid,y),val); 21 if(y>mid) change(k<<1|1,mid+1,r,max(x,mid+1),y,val); 22 } 23 int query(int k,int l,int r,int x,int y) 24 { 25 if(l==x&&y==r) return v[k]; 26 int mid=(l+r)>>1,ans=tag[k]; 27 if(x<=mid) ans=max(ans,query(k<<1,l,mid,x,min(mid,y))); 28 if(y>mid) ans=max(ans,query(k<<1|1,mid+1,r,max(x,mid+1),y)); 29 return ans; 30 } 31 }; 32 struct segy 33 { 34 segx v[3005],tag[3005]; 35 void change(int k,int l,int r,int x,int y,int val) 36 { 37 v[k].change(1,1,S,qd,qu,val); 38 if(l==x&&y==r) {tag[k].change(1,1,S,qd,qu,val);return;} 39 int mid=(l+r)>>1; 40 if(x<=mid) change(k<<1,l,mid,x,min(mid,y),val); 41 if(y>mid) change(k<<1|1,mid+1,r,max(x,mid+1),y,val); 42 } 43 int query(int k,int l,int r,int x,int y) 44 { 45 if(l==x&&y==r) return v[k].query(1,1,S,qd,qu); 46 int mid=(l+r)>>1,ans=tag[k].query(1,1,S,qd,qu); 47 if(x<=mid) ans=max(ans,query(k<<1,l,mid,x,min(mid,y))); 48 if(y>mid) ans=max(ans,query(k<<1|1,mid+1,r,max(x,mid+1),y)); 49 return ans; 50 } 51 }T; 52 int main() 53 { 54 D=read();S=read();N=read(); 55 int d,s,w,x,y; 56 for(int i=1;i<=N;i++) 57 { 58 d=read();s=read();w=read();x=read();y=read(); 59 ql=x+1;qr=x+d;qd=y+1;qu=y+s; 60 int ans=T.query(1,1,D,ql,qr); 61 T.change(1,1,D,ql,qr,ans+w); 62 } 63 qd=1,qu=S; 64 printf("%d ",T.query(1,1,D,1,D)); 65 return 0; 66 }