数据结构:树套树-线段树套线段树

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 }
原文地址:https://www.cnblogs.com/aininot260/p/9375048.html