1. 程式人生 > >BZOJ1513:樹套樹之線段樹套線段樹實現二維區間修改和最值查詢

BZOJ1513:樹套樹之線段樹套線段樹實現二維區間修改和最值查詢

name names algo getch oid min 投影 協調 pan

我們經常提及的二維線段樹有兩種寫法,一種是四分樹,一種是樹套樹,寫成四分樹的都是神仙。

樹套樹寫法還是比較好理解的,不過要是讓自己硬套的話可能很不容易套出來的

這裏的二維線段樹,外層線段樹是對方陣的正投影,而內層線段樹是對方陣的側投影

這裏的內層線段樹可以變換成一棵普通的帶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\n",T.query(1,1,D,1,D));
65     return 0;
66 }

BZOJ1513:樹套樹之線段樹套線段樹實現二維區間修改和最值查詢