poj1151 Atlantis (线段树+扫描线+离散化)
有点难,扫描线易懂,离散化然后线段树处理有点不太好理解。
因为这里是一个区间,所有在线段树中更新时,必须是一个长度大于1的区间才是有效的,比如[l,l]这是一根线段,而不是区间了。
AC代码
#include <stdio.h> #include <map> #include <vector> #include <algorithm> using namespace std; const int maxn = 200 + 5; struct Line{ double x, y1, y2; int flag; Line(double a, double b, double c, int d) { x = a; y1 = b; y2 = c; flag = d; } bool operator < (const Line& a) const { return x < a.x; } }; vector<Line> line; map<double, int> Hash; vector<double> y; double p[maxn << 2]; // 区间长度 int covers[maxn << 2]; // 覆盖次数 double len[maxn << 2]; // 覆盖长度 void buildTree(int o, int l, int r) { len[o] = covers[o] = 0; p[o] = y[r] - y[l]; if(l + 1 != r) { int m = (l+r) / 2; buildTree(o*2, l, m); buildTree(o*2+1, m, r); } } int ul, ur; void update(int o, int l, int r, int f) { if(l+1 == r) { covers[o] += f; if(covers[o] == 0) len[o] = 0; else len[o] = p[o]; } else { int m = (l+r) / 2; if(ul < m) update(o*2, l, m, f); if(m < ur) update(o*2+1, m, r, f); // pushUp len[o] = len[o*2] + len[o*2+1]; } } int main() { int n, kase = 1; while(scanf("%d", &n) == 1 && n) { Hash.clear(); line.clear(); y.clear(); double x1, y1, x2, y2; for(int i = 0; i < n; i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); line.push_back(Line(x1, y1, y2, 1)); line.push_back(Line(x2, y1, y2, -1)); y.push_back(y1); y.push_back(y2); } sort(line.begin(), line.end()); sort(y.begin(), y.end()); y.erase(unique(y.begin(), y.end()), y.end()); for(int i = 0; i < (int)y.size(); i++) { Hash[y[i]] = i; } buildTree(1, 0, y.size()-1); double ans = 0; for(int i = 0; i < line.size(); i++) { if(i > 0) ans += (line[i].x - line[i-1].x) * len[1]; ul = Hash[line[i].y1]; ur = Hash[line[i].y2]; update(1, 0, y.size()-1, line[i].flag); } printf("Test case #%d\nTotal explored area: %.2f\n\n", kase++, ans); } return 0; }
如有不当之处欢迎指出!