【POJ 2482】【掃描線問題】Stars in Your Window【包星星問題】
阿新 • • 發佈:2018-11-19
題意:
給出一大堆星星的座標,給出每個星星的亮度。然後給出一個矩形,要求用這個矩形包住的星星的亮度最大。注意:如果星星在矩形邊界上,則不計算這個星星的亮度。
【ps:本題的description是一封極美的情書,文采非常棒,強推!】
思路:
我們來思考一下,一個矩形的位置是不是由這個矩形右上角這個點所決定的,所以我們可以把考慮矩形的位置改為考慮右上角這個點所在的位置。
然後我們可以發現,對於一顆星星,(x,y),只要右上角這個點在(x+0.1,y+0.1)~(x+w-0.1,y+h-0.1)這個範圍內,即可包住這顆星星。此處取0.1的原因是星星不能在矩形邊界上。
因此一個星星就可以確定一個矩形,那麼本題就變成了給出一大堆矩形,每個矩形都有一個權值,問其中哪一個區域矩形值之和最大。
因此我們可以將每個矩形的左右邊界抽離出來,然後就變成了區間覆蓋問題。
詢問線上段樹維護下的這根掃描線上亮度最大的值是多少,所以線段樹上只需要維護一個最大值,再加上一個lazy標記,然後邊插入邊,邊更新ans,就可以通過此題。
總結:
掃描線的問題都大同小異,核心在於求出由線段樹維護的這一根線上被覆蓋的最長長度,或者某一個亮度最大的點的值,維護一下sum或者維護一下max就可以解決問題。
關鍵點還是在於如何掃的問題上,弄清楚如何掃,接下來的就只是碼程式碼了。
程式碼:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define rep(i,a,b) for(int i = a; i <= b; i++) using namespace std; const int N = 100000; struct Line{ double x,y1,y2; int flag; }line[N]; bool cmp(Line a,Line b) { return a.x < b.x; } int n,w,h,num,ans; double y[N]; struct Tree{ int l,r,lazy; double ml,mr; int maxn; }t[N*4]; void build(int p,int l,int r) { t[p].l = l, t[p].r = r, t[p].ml = y[l], t[p].mr = y[r], t[p].maxn = 0, t[p].lazy = 0; if(l == r) return; int mid = (l+r)>>1; build(p*2,l,mid); build(p*2+1,mid+1,r); } void pushup(int p) { if(t[p].lazy != 0) { t[p*2].lazy += t[p].lazy; t[p*2+1].lazy += t[p].lazy; t[p*2].maxn += t[p].lazy; t[p*2+1].maxn += t[p].lazy; t[p].lazy = 0; } } void change(int p, Line a) { // cout << a.y1 << " " << a.y2 << endl; if(a.y1 <= t[p].ml && t[p].mr <= a.y2) { // t[p].s += a.flag; t[p].lazy += a.flag; t[p].maxn += a.flag; return; } pushup(p); if(t[p*2].mr >= a.y2) change(p*2,a); else if(t[p*2+1].ml <= a.y1) change(p*2+1,a); else{ change(p*2,a); change(p*2+1,a); } t[p].maxn = max(t[p*2].maxn,t[p*2+1].maxn); } int main() { while(~scanf("%d%d%d",&n,&w,&h)) { ans = 0, num = 0; rep(i,1,n) { double x1,y1,z1; scanf("%lf%lf%lf",&x1,&y1,&z1); line[++num].x = x1+0.1, line[num].y1 = y1+0.1, line[num].y2 = y1+h-0.1, y[num] = y1+0.1, line[num].flag = z1; line[++num].x = x1+w-0.1, line[num].y1 = y1+0.1, line[num].y2 = y1+h-0.1, y[num] = y1+h-0.1, line[num].flag = -z1; } sort(line+1,line+1+num,cmp); sort(y+1,y+1+num); int scr = unique(y+1,y+1+num)-y-1; build(1,1,scr); rep(i,1,num) { change(1,line[i]); ans = max(ans,t[1].maxn); } printf("%d\n",ans); } return 0; }