1. 程式人生 > >[POI2006]TET-Tetris 3D

[POI2006]TET-Tetris 3D

一是 char 線段 www 不用 節點 span rep 修改

傳送門

要做這道題我們需要兩個前置技能:二維線段樹和標記永久化。

我們使用一維線段樹來維護一個序列,那我們想維護一個矩陣的時候,二維線段樹應運而生。

二維線段樹好像有兩種實現方法。一是對於每一個節點(x軸上的每個點)在裏面再開一棵線段樹(表示一個y軸)(這好像更多人管他叫樹套樹做法?)

第二個是把它變成一棵四叉樹……不過這種實現方法我並沒有學。

具體的實現方法其實非常優秀,可以選擇寫結構體。就是對於一次修改,正常在我們一維線段樹上傳6個參數,我們再多傳兩個記錄y軸修改範圍的參數,然後在到達制定修改位置的時候我們進入y軸去修改即可。(這個可以一會看代碼)

之後再說說標記永久化,我們在進行區間修改的時候是要pushdown的,但是這個對於樹套樹等等比較復雜的數據結構是很麻煩的,而且尤其是像這道題,你不知道怎麽下放。所以我們進行標記永久化。以區間加法為例,我們維護sum和add兩個標記,在修改到指定位置之前,每經過一個區間就把他的sum加上加的值*區間長度。然後在修改到指定位置(完全覆蓋的時候)我們把這個區間的add加上加的值。

然後在每次之後的查詢中,我們每次向下走,都要加上這個區間所貢獻的add*區間長度,這樣才是結果(註意區間完全覆蓋的時候不加,因為這個已經算在sum裏面了)

那我們現在來看這道題。題目翻譯的太好了,特別簡練,而且是直接告訴你要幹啥而不是讓你再總結一遍。

我們用二維線段樹維護這個序列。對於每次修改,我們先查詢這個矩陣內的最大值,然後直接改成最大值+h的高度就行。

在途中是可以標記永久化的。這個思路和區間加法是一樣的,不過這個變成了永久取最大值,所以在每次下放的時候更新當前mx(最大值),直到區間完全覆蓋更新tag(修改後最大值),在query的時候對於一個區間,所有query的值都要與這個區間的tag去比較,然後返回較大值。

看一下代碼。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)
#define pr pair<int,int>
#define
mp make_pair #define fi first #define sc second using namespace std; typedef long long ll; const int M = 100005; const int N = 8005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < 0 || ch > 9) { if(ch == -) op = -1; ch = getchar(); } while(ch >=0 && ch <= 9) { ans *= 10; ans += ch - 0; ch = getchar(); } return ans * op; } int d,s,h,x,y,k,n,m; struct segy//維護y軸 { int mx[N],tag[N]; void change(int p,int l,int r,int kl,int kr,int val) { mx[p] = max(mx[p],val);//更新(標記永久化) if(l == kl && r == kr) { tag[p] = max(tag[p],val);//區間完全覆蓋的時候更新 return; } int mid = (l+r) >> 1;//一切正常 if(kr <= mid) change(p<<1,l,mid,kl,kr,val); else if(kl > mid) change(p<<1|1,mid+1,r,kl,kr,val); else change(p<<1,l,mid,kl,mid,val),change(p<<1|1,mid+1,r,mid+1,kr,val); } int query(int p,int l,int r,int kl,int kr) { if(l == kl && r == kr) return mx[p];//完全覆蓋 int cur = tag[p],mid = (l+r) >> 1;//剩下的所有與tag比較 if(kr <= mid) cur = max(query(p<<1,l,mid,kl,kr),cur); else if(kl > mid) cur = max(query(p<<1|1,mid+1,r,kl,kr),cur); else cur = max(cur,max(query(p<<1,l,mid,kl,mid),query(p<<1|1,mid+1,r,mid+1,kr))); return cur; } }; struct segx//維護x軸 { segy mx[N],tag[N]; void change(int p,int l,int r,int kl,int kr,int zl,int zr,int val) { mx[p].change(1,1,m,zl,zr,val);//每次都修改(標記永久化) if(l == kl && r == kr) { tag[p].change(1,1,m,zl,zr,val);//只有完全覆蓋才修改 return; } int mid = (l+r) >> 1;//剩下的很正常 if(kr <= mid) change(p<<1,l,mid,kl,kr,zl,zr,val); else if(kl > mid) change(p<<1|1,mid+1,r,kl,kr,zl,zr,val); else change(p<<1,l,mid,kl,mid,zl,zr,val),change(p<<1|1,mid+1,r,mid+1,kr,zl,zr,val); } int query(int p,int l,int r,int kl,int kr,int zl,int zr) { if(l == kl && r == kr) return mx[p].query(1,1,m,zl,zr); int cur = tag[p].query(1,1,m,zl,zr),mid = (l+r) >> 1; if(kr <= mid) cur = max(cur,query(p<<1,l,mid,kl,kr,zl,zr)); else if(kl > mid) cur = max(cur,query(p<<1|1,mid+1,r,kl,kr,zl,zr)); else cur = max(cur,max(query(p<<1,l,mid,kl,mid,zl,zr),query(p<<1|1,mid+1,r,mid+1,kr,zl,zr))); return cur;//這裏每次在修改的時候都要與tag比較,完全覆蓋的時候不用,因為已經更新過了 } }t; int main() { n = read(),m = read(),k = read(); while(k--) { d = read(),s = read(),h = read(),x = read(),y = read(); int g = t.query(1,1,n,x+1,x+d,y+1,y+s);//查詢最大值 t.change(1,1,n,x+1,x+d,y+1,y+s,g+h);//區間修改 } printf("%d\n",t.query(1,1,n,1,n,1,m)); return 0; }

[POI2006]TET-Tetris 3D