1. 程式人生 > >Atlantis HDU - 1542 線段樹 掃描線

Atlantis HDU - 1542 線段樹 掃描線

題解

題目大意 給你n個矩形的左上角座標和右下角座標求矩形覆蓋面積 座標為實數

使用線段樹+掃描線求解
將矩形分割為上下兩條邊 記錄邊的左端點和右端點分別對應矩形的左右側邊 上下邊的高度分別對應矩形的上下邊 和符號 上為正下為負
將邊按照高度從高到低排序處理 每次處理過程中根據符號線上段樹中離散化標記覆蓋範圍並計算覆蓋長度 乘上距離下條邊的高度差為當前分塊的答案貢獻 求和即可

AC程式碼

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long
ll; const int INF = 0x3f3f3f3f; const int MAXN = 210; //*2 vector<double> dz; //離散化型別為double。。 struct node { int l, r; int cnt; //葉節點覆蓋次數 double sum; //區間覆蓋長度和 }tre[MAXN * 4]; struct node2 { double l, r, h; //橫向邊 int f; //狀態 bool operator < (const node2 &oth) { return
h < oth.h; } }a[MAXN]; inline void PushUp(int x) { if (tre[x].cnt) //當前區間被覆蓋 tre[x].sum = dz[tre[x].r + 1] - dz[tre[x].l]; //區間長度 else if (tre[x].l == tre[x].r) //一個點 tre[x].sum = 0; else tre[x].sum = tre[x << 1].sum + tre[x << 1 | 1].sum; //合併左右兒子 } void
Build(int x, int l, int r) { tre[x].l = l, tre[x].r = r, tre[x].cnt = tre[x].sum = 0; if (l == r) return; int m = l + r >> 1; Build(x << 1, l, m); Build(x << 1 | 1, m + 1, r); } void Update(int x, int pl, int pr, int v) //區間更新不用lzay { int l = tre[x].l, r = tre[x].r; if (pl <= l && r <= pr) { tre[x].cnt += v; //加一或者減一 PushUp(x); //更新一下 } else { int m = l + r >> 1; if (pl <= m) Update(x << 1, pl, pr, v); if (pr > m) Update(x << 1 | 1, pl, pr, v); PushUp(x); } } int Dis(double v) { return lower_bound(dz.begin(), dz.end(), v) - dz.begin(); } int main() { #ifdef LOCAL freopen("C:/input.txt", "r", stdin); #endif int N, kase = 1; while (cin >> N, N) { dz.clear(); dz.push_back(-INF); for (int i = 1; i <= N; i++) //將矩形拆分為一正一負兩條橫向邊 { double x1, y1, x2, y2; scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); a[i * 2 - 1] = { y1, y2, x1, 1 }; a[i * 2] = { y1, y2, x2, -1 }; dz.push_back(y1), dz.push_back(y2); //離散化縱座標 } N *= 2; sort(a + 1, a + N + 1); //按照高度從上到下排序 sort(dz.begin(), dz.end()); dz.erase(unique(dz.begin(), dz.end()), dz.end()); Build(1, 1, N); double ans = 0.0; for (int i = 1; i < N; i++) //從上向下掃描 不掃描最後一個 { Update(1, Dis(a[i].l), Dis(a[i].r) - 1, a[i].f); //更新[l, r)範圍 ans += (a[i + 1].h - a[i].h) * tre[1].sum; //到下一個線段的高度差*整個縱座標範圍的覆蓋面積 } printf("Test case #%d\n", kase++); printf("Total explored area: %.2f\n\n", ans); } return 0; }