火星探险 (Mars)
暫無鏈接
題目描述
在2051年,若干火星探險隊探索了這顆紅色行星的不同區(qū)域并且制作了這些區(qū)域的地圖。現(xiàn)在,Baltic空間機構有一個雄心勃勃的計劃,他們想制作一張整個行星的地圖。為了考慮必要的工作,他們需要知道地圖上已經(jīng)存在的全部區(qū)域的大小。你的任務是寫一個計算這個區(qū)域大小的程序。
具體任務要求為:
(1)從輸入中讀取地圖形狀的描述;
(2)計算地圖覆蓋的全部的區(qū)域;
(3)輸出探索區(qū)域的總面積(即所有矩形的公共面積)。
輸入格式
輸入的第一行包含一個整數(shù)n(1≤n≤10000)(1≤n≤10000),表示可得到的地圖數(shù)目。
以下n行,每行描述一張地圖。每行包含4個整數(shù)x1,y1,x2和y2(0≤x1<x2≤300000≤x1<x2≤30000,0≤y1<y2≤300000≤y1<y2≤30000)。數(shù)值(x1,y1)(x1,y1)和(x2,y2)(x2,y2)是坐標,分別表示繪制區(qū)域的左下角和右上角坐標。每張地圖是矩形的,并且它的邊是平行于x坐標軸或y坐標軸的。
輸出格式
輸出文件包含一個整數(shù),表示探索區(qū)域的總面積(即所有矩形的公共面積)。
輸入樣例
2
10 10 20 20
15 15 25 30
輸出樣例
225
解題分析:
赤裸裸的掃描線…和 窗口的星星 的思路一樣, 將x坐標離散化, 將上下底按y軸坐標排序, 用線段樹維護當前存在的矩形下底。
我們可以將下底權值設為1,上底權值設為-1, 每次更新線段樹區(qū)間后將面積加上當前可用的下底乘上與下一條底邊間高度的差。
關鍵在于如何維護底的長度。 我們可以在線段樹中維護一個值lenlen表示當前區(qū)間可用的總長度, 以及另一個值validvalid表示當前區(qū)間是否可用。我們每次更新(加入一條新的邊)時就更新根據(jù)valid值更新。有三種情況:
1.valid!=0valid!=0:說明當前區(qū)間可用, 所以當前區(qū)域的可用底邊長度即為xright?xleft?1xright?xleft?1
2.valid=0valid=0且lef=riglef=rig:說明當前點已沒有線段覆蓋,可用長度為0。
3.其他情況:即lef!=riglef!=rig且valid=0valid=0, 說明之前可能有modify到更小子區(qū)域的情況,(在這里valid并不是向上傳導的), 所以當前區(qū)域的可用底邊長度為len(sonleft)+len(sonright)len(sonleft)+len(sonright)。這個性質的前提是:因為每條下底都有對應的上底, 所以當上底加入時區(qū)間中還有可能有可用的區(qū)間底邊,且不會與抵消了的下底重復, 因為加入下底的時候并沒有將lenlen下傳到下一層的點, 下一層的len只可能是其他邊賦上的。
下面上代碼:
#include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <algorithm> #include <cmath> #define R register #define gc getchar() #define W while #define IN inline #define MX 50005 #define db double template <typename T> IN void in(T &x) {x = 0; R char c = gc;W (!isdigit(c)) c = gc;W (isdigit(c)){x = (x << 1) + (x << 3), x += c - 48, c = gc;} } namespace SGT {#define ls now << 1#define rs now << 1 | 1int x[MX], left[MX], right[MX];int num, tot, cnt;struct Edge{int x, y, id, typ;}data[MX << 1], anti[MX << 1];IN bool cmp_x (const Edge &x, const Edge &y){return x.x < y.x;}IN bool cmp_y (const Edge &x, const Edge &y){return x.y == y.y ? x.typ > y.typ : x.y < y.y;}//在這里和窗口的星星一題不同的是, 其實不必將負值的邊排在前面,因為有多條邊的時候它們之間的高為0IN bool operator == (const Edge &x, const Edge &y){return x.x == y.x;}struct Node{int valid, lef, rig, len; }tree[MX << 1];void build(int now, int l, int r){tree[now].lef = l, tree[now].rig = r;if(l == r) return;int mid = (l + r) >> 1;build(ls, l, mid);build(rs, mid + 1, r);}IN void pushup(const int &now){if(tree[now].valid) tree[now].len = x[tree[now].rig ] - x[tree[now].lef - 1];//因為保存的為點, 為了不少加區(qū)間之間的那部分,左端點需要減一else if(tree[now].lef == tree[now].rig) tree[now].len = 0; else tree[now].len = tree[ls].len + tree[rs].len;}void modify(const int &now, const int &lb, const int &rb, const int &delta){if(tree[now].lef == lb && tree[now].rig == rb){tree[now].valid += delta;pushup(now);return;}int mid = (tree[now].lef + tree[now].rig) >> 1;if(mid >= rb) modify(ls, lb, rb, delta);else if(mid < lb) modify(rs, lb, rb, delta);else{modify(ls, lb, mid, delta);modify(rs, mid + 1, rb, delta);}pushup(now);} } using namespace SGT; using std::sort; using std::unique; int main() {int lf, dn, rg, up;in(num);for (R int i = 1; i <= num; ++i){in(lf), in(dn), in(rg), in(up);data[++tot].x = lf, data[tot].id = i, data[tot].typ = 0;anti[tot].y = dn, anti[tot].id = i, anti[tot].typ = 0;data[++tot].x = rg, data[tot].id = i, data[tot].typ = 1;anti[tot].y = up, anti[tot].id = i, anti[tot].typ = 1;}sort(data + 1, data + 1 + tot, cmp_x);sort(anti + 1, anti + 1 + tot, cmp_y);for (R int i = 1; i <= tot; ++i){//離散化if(i == 1 || data[i].x != data[i - 1].x) ++cnt;x[cnt] = data[i].x;if(!data[i].typ) left[data[i].id] = cnt;else right[data[i].id] = cnt;}build(1, 1, cnt);int ans = 0;for (R int i = 1; i < tot; ++i){if(!anti[i].typ)modify(1, left[anti[i].id] + 1, right[anti[i].id], 1);else//因為modify的時候lef減了一,所以這里要加上modify(1, left[anti[i].id] + 1, right[anti[i].id], -1);ans += (anti[i + 1].y - anti[i].y) * tree[1].len;}printf("%d", ans);return 0; }總結
以上是生活随笔為你收集整理的火星探险 (Mars)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机上机考试自我检查800字,【考试太
- 下一篇: 安卓字体设置大全