Poj2482 Stars in Your Window(掃描線)
阿新 • • 發佈:2019-01-22
lock href cpp 一個 window 之間 問題 const ref
題面
Poj
題解
下面內容引用自"李煜東 《算法競賽進階指南》"(對原文略有縮減,侵刪):
因為矩形的大小固定,所以矩形可以由它的任意一個頂點唯一確定。我們可以考慮把矩形的右上角頂點放在什麽位置,圈住的星星亮度總和最大。
所以,對於一顆星星,能夠覆蓋住這顆星星的右上角的位置在區間\([x,y]-[x+w,y+h]\)之間,但是由於邊界上的星星不算,所以不妨將星星變為\([x-0.5,y-0.5]\),於是右上角變為\([x+w-1,y+h-1]\)。
問題就轉化成了:平面上有若幹個區域,每個區域都帶有一個權值,求在哪個坐標上重疊的區域權值和最大。可以用掃描線算法來解決。
具體來說,將一顆星星抽象成一個矩形,取出左右邊界(四元組):\((x,y,y+h-1,c)\)
和\((x+w,y,y+h-1,-c)\),然後按照橫坐標排序。關於縱坐標建立一顆線段樹,維護區間最大值\(dat\),初始全為\(0\),線段樹上的一個值\(y\)表示區間\([y,y+1]\),註意掃描每個四元組\((x,y_1,y_2,c)\),執行區間修改,把\([y1,y2]\)中的每一個數都加\(c\),用根節點\(dat\)更新就好了。
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using std::min; using std::max; using std::swap; using std::sort; using std::unique; using std::lower_bound; typedef long long ll; #define int ll template<typename T> void read(T &x) { int flag = 1; x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); } while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag; } const int N = 2e4 + 10; ll n, W, H; ll cf[N << 1], tot; struct star { ll x, y, h; } s[N]; struct raw { ll x, y1, y2, d; } cy[N << 1]; int cnt; inline bool cmp (const raw &a ,const raw &b) { return a.x < b.x || (a.x == b.x && a.d < b.d); } ll val[N << 4], add[N << 4]; void pushdown(int o, int lc, int rc) { if(add[o]) { add[lc] += add[o], add[rc] += add[o]; val[lc] += add[o], val[rc] += add[o], add[o] = 0; } } void modify (int ml, int mr, ll k, int o = 1, int l = 1, int r = tot) { if(l >= ml && r <= mr) { val[o] += k, add[o] += k; return ; } int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; pushdown(o, lc, rc); if(ml <= mid) modify(ml, mr, k, lc, l, mid); if(mr > mid) modify(ml, mr, k, rc, mid + 1, r); val[o] = max(val[lc], val[rc]); } signed main () { while(scanf("%lld%lld%lld", &n, &W, &H) != EOF) { cnt = tot = 0; ll ans = 0; for(int i = 1; i <= n; ++i) { read(s[i].x), read(s[i].y), read(s[i].h); cy[++cnt] = (raw){s[i].x, s[i].y, s[i].y + H - 1, s[i].h}; cy[++cnt] = (raw){s[i].x + W, s[i].y, s[i].y + H - 1, -s[i].h}; cf[++tot] = s[i].y, cf[++tot] = s[i].y + H - 1; } sort(&cf[1], &cf[tot + 1]), tot = unique(&cf[1], &cf[tot + 1]) - cf - 1; sort(&cy[1], &cy[cnt + 1], cmp); memset(val, 0, sizeof val), memset(add, 0, sizeof add); for(int i = 1; i <= cnt; ++i) { cy[i].y1 = lower_bound(&cf[1], &cf[tot + 1], cy[i].y1) - cf; cy[i].y2 = lower_bound(&cf[1], &cf[tot + 1], cy[i].y2) - cf; modify(cy[i].y1, cy[i].y2, cy[i].d); ans = max(ans, val[1]); } printf("%lld\n", ans); } return 0; }
Poj2482 Stars in Your Window(掃描線)