您的位置:首页 > 其它

【线段树 + 离散化 + 扫描线】poj 1151 Atlantis 矩形面积并

2014-11-06 11:14 447 查看
将所有的线段按照x左边从小到大排序,并对所有的横纵坐标进行离散化,从左到右扫描,每碰到一条矩形左侧的线段,就插入线段树;每碰到一条矩形右侧的线段,就从线段树中删除。同时线段树中每个节点要维护一个计数变量,应对一个区间被多个矩形覆盖的情形。

#include <vector>
#include <list>
#include <limits.h>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string.h>
#include <stdlib.h>
#include <cassert>
using namespace std;

struct Node {
double total;
int left, right, lc, rc, cnt;
Node() {
total = cnt = 0;
left = right = lc = rc = -1;
}
};
Node tree[1500];

struct Line {
double x, y1, y2;
bool left;
Line(double _x, double _y1, double _y2, bool _left): x(_x), y1(_y1), y2(_y2), left(_left) {}
};

bool cmp(const Line& i, const Line& j) { return i.x < j.x; }

int n, ptr;
vector<Line> lines;
vector<double> ys;

int get(double y) {
for (int i = 0; i < ys.size(); ++i) {
if (fabs(y - ys[i]) < 1e-6) return i;
}
assert(false); // should not reach here
return -1;
}

void build_tree(int low, int up, int cur) {
tree[cur].left = low;
tree[cur].right = up;
if (up - low <= 1) return;
int mid = (low + up) / 2;
++ptr; tree[cur].lc = ptr;
build_tree(low, mid, ptr);
++ptr; tree[cur].rc = ptr;
build_tree(mid, up, ptr);
return;
}

void update_node(int root) {
if (tree[root].cnt > 0) {
tree[root].total = ys[tree[root].right] - ys[tree[root].left];
return;
}
if (tree[root].right - tree[root].left <= 1) {
tree[root].total = 0;
return;
}
else {
tree[root].total = tree[tree[root].lc].total + tree[tree[root].rc].total;
return;
}
}

void insert_node(int low, int up, int cur) {
// cout << "insert: " << low << " " << up << " " << cur << endl;
if (low <= tree[cur].left && up >= tree[cur].right) {
++tree[cur].cnt;
update_node(cur);
return;
}
assert(tree[cur].right - tree[cur].left > 1);
int mid = (tree[cur].left + tree[cur].right) / 2;
if (up <= mid) { insert_node(low, up, tree[cur].lc); }
else if (low >= mid) { insert_node(low, up, tree[cur].rc); }
else {
insert_node(low, mid, tree[cur].lc);
insert_node(mid, up, tree[cur].rc);
}
update_node(cur);
return;
}

void delete_node(int low, int up, int cur) {
if (low <= tree[cur].left && up >= tree[cur].right) {
assert(tree[cur].cnt > 0);
--tree[cur].cnt;
update_node(cur);
return;
}
assert(tree[cur].right - tree[cur].left > 1);
int mid = (tree[cur].left + tree[cur].right) / 2;
if (up <= mid) { delete_node(low, up, tree[cur].lc); }
else if (low >= mid) { delete_node(low, up, tree[cur].rc); }
else {
delete_node(low, mid, tree[cur].lc);
delete_node(mid, up, tree[cur].rc);
}
update_node(cur);
return;
}

int main() {
int t = 1;
while (cin >> n && n) {
double x1, y1, x2, y2;
lines.clear(); ys.clear(); ptr = 0;
for (int i = 0; i < 1500; ++i) {
tree[i].total = tree[i].cnt = 0;
tree[i].left = tree[i].right = tree[i].lc = tree[i].rc = -1;
}
for (int i = 0; i < n; ++i) {
cin >> x1 >> y1 >> x2 >> y2;
lines.push_back(Line(x1, y1, y2, true));
lines.push_back(Line(x2, y1, y2, false));
ys.push_back(y1); ys.push_back(y2);
}
sort(lines.begin(), lines.end(), cmp);
sort(ys.begin(), ys.end());
double area = 0;
build_tree(0, ys.size(), 0);
for (int i = 0; i + 1 < lines.size(); ++i) {
Line tmp = lines[i];
if (tmp.left) insert_node(get(tmp.y1), get(tmp.y2), 0);
else delete_node(get(tmp.y1), get(tmp.y2), 0);
area += tree[0].total * (lines[i + 1].x - tmp.x);
}
cout << "Test case #" << t++ << endl;
cout << "Total explored area: " << fixed << setprecision(2) << area << endl;
cout << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: