|
题目链接:http://poj.org/problem?id=3277
/**//* 题意: 给定N(N <= 40000)个矩形,求它们的面积并。
解法: 离散化+线段树
思路: 矩形面积并的nlog(n)经典算法。首先我们将每个矩形的纵向边投 影到Y轴上,这样就可以把矩形的纵向边看成一个闭区间,用线段树来 维护这些矩形边的并。现在求的是矩形的面积并,于是可以枚举矩形的 x坐标,然后检测当前相邻x坐标上y方向的合法长度,两者相乘就是其中 一块面积,枚举完毕后就求得了所有矩形的面积并。 我的线段树结点描述保存了以下信息:区间的左右端点、结点所在 数组编号(因为采用静态结点可以大大节省申请空间的时间)、该结点 被竖直线段完全覆盖的次数Cover和当前结点的测度。测度是指相邻x坐 标之间有效的y方向的长度的和(要求在该区间内)。于是重点就在于 如何维护测度,我们将一个矩形分成两条竖直线段来存储,左边的边称 为入边,右边的边则为出边,然后把所有这些竖直线段按照x坐标递增排 序,每次进行插入操作,因为坐标有可能不是整数,所以必须在做这些 之前将y方向的坐标离散化到数组中,每次插入时如果当前区间被完全覆 盖,那么就要对Cover域进行更新,入边+1,出边-1。更新完毕后判断当 前结点的Cover域是否大于零,如果大于零那么当前节点的测度就是结点 管理区间在y轴上的实际长度,否则,如果是叶子节点,那么测度为0, 如果是内部结点,那么测度的值是左右儿子测度的和。这个更新是log(n) 的,所以,总的复杂度就是nlog(n)。 */
#include <iostream> #include <vector> #include <algorithm> using namespace std;
#define maxn 100010 #define ll __int64
struct VLine { int x, y0, y1; int v; VLine() {} VLine(int _x, int _y0, int _y1, int _v) { x = _x; y0 = _y0; y1 = _y1; v = _v; } };
int cmp(VLine a, VLine b) { return a.x < b.x; }
vector< VLine > Vl;
int tmp[maxn], size, tot;
int n;
int Binary(int val) { int l = 0; int r = tot-1; while(l <= r) { int m = (l + r) >> 1; if(tmp[m] == val) return m; if(val > tmp[m]) { l = m + 1; }else r = m - 1; } }
struct Tree { int l, r, root; int nCover; int ylen;
void Update(); }T[maxn*4];
void Tree::Update() { if(nCover) { ylen = tmp[r] - tmp[l]; }else { if(l + 1 == r) ylen = 0; else ylen = T[root<<1].ylen + T[root<<1|1].ylen; } }
void Build(int root, int l, int r) { T[root].l = l; T[root].r = r; T[root].root = root; T[root].nCover = T[root].ylen = 0; if(l + 1 == r) return ; int mid = (l + r) >> 1; Build(root<<1, l, mid); Build(root<<1|1, mid, r); }
void Insert(int root, int l, int r, int val) { if(l >= T[root].r || T[root].l >= r) return ;
if(l <= T[root].l && T[root].r <= r) { T[root].nCover += val; T[root].Update(); return ; } Insert(root<<1, l, r, val); Insert(root<<1|1, l, r, val);
T[root].Update(); }
int main() { int i; while(scanf("%d", &n) != EOF) { Vl.clear(); size = tot = 0; tmp[size++] = 0;
for(i = 0; i < n; i++) { int x0, x1, y; scanf("%d %d %d", &x0, &x1, &y); Vl.push_back(VLine(x0, 0, y, 1)); Vl.push_back(VLine(x1, 0, y, -1)); tmp[size++] = y; }
sort(Vl.begin(), Vl.end(), cmp); sort(tmp, tmp + size);
for(i = 0; i < size; i++) { if(!i || tmp[i] != tmp[i-1]) { tmp[tot++] = tmp[i]; } }
ll ans = 0; Build(1, 0, tot-1);
for(i = 0; i < Vl.size(); i++) { if(i) { ans += (ll)(Vl[i].x - Vl[i-1].x) * T[1].ylen; } Insert(1, Binary(Vl[i].y0), Binary(Vl[i].y1), Vl[i].v); }
printf("%I64d\n", ans); }
return 0; }
|