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

将所有的线段按照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;
}


你可能感兴趣的:(【线段树 + 离散化 + 扫描线】poj 1151 Atlantis 矩形面积并)