题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1542
与以往线段树不同的地方是区间[l, r]表示的是线段为[l, r + 1],因为比如说对区间[1, 4]建树,它的儿子分别为[1, 2]和[3, 4],如果直接用这个区间表示线段,则2到3这部分没有了。特别的,当l==r时,结点[l, r]是指一条长度为1的线段,它起点为l,终点为l + 1。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<utility>
using namespace std;
#define LL long long
#define FUCK cout << "Ca!" << endl;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const double eps = 1e-8;
const int maxn = 2222;
struct Square
{
double x1, y1, x2, y2;
}sq[maxn];
struct Segment
{
double h;
int l, r, mark;
}e[maxn << 1];
double sum[maxn << 2], yy[maxn << 1], Y[maxn << 1];
int cal[maxn << 2], cnt;
bool cmp(Segment a, Segment b)
{
return a.h < b.h;
}
void build(int l, int r, int rt)
{
cal[rt] = 0;
sum[rt] = 0;
if (l == r) return;
int mid = (l + r) >> 1;
build(lson);
build(rson);
}
double dcmp(double num)
{
if (fabs(num) < eps) return 0;
if (num < 0) return -1;
else return 1;
}
double Bin(double num)
{
int l = 1, r = cnt;
while (l <= r)
{
int mid = (l + r) >> 1;
if (dcmp(yy[mid] - num) < 0) l = mid + 1;
else r = mid - 1;
}
return l;
}
void Edge(int i, double h, double l, double r, int mark)
{
e[i].h = h;
e[i].mark = mark;
e[i].l = Bin(l);
e[i].r = Bin(r);
}
void pushup(int rt, int l, int r)
{
if (cal[rt]) sum[rt] = yy[r + 1] - yy[l];
else
if (l == r) sum[rt] = 0;
else sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void update(int L, int R, int mark, int l, int r, int rt)
{
if (L <= l && R >= r)
{
cal[rt] += mark;
pushup(rt, l, r);
return;
}
int mid = (l + r) >> 1;
if (L <= mid) update(L, R, mark, lson);
if (R > mid) update(L, R, mark, rson);
pushup(rt, l, r);
}
int main()
{
int n, kase = 0;
while (cin >> n)
{
if (n == 0) break;
++kase;
int i;
//把y坐离散化
for (i = 0; i < n; i++)
{
cin >> sq[i].x1 >> sq[i].y1 >> sq[i].x2 >> sq[i].y2;
Y[i * 2] = sq[i].y1;
Y[i * 2 + 1] = sq[i].y2;
}
sort(Y, Y + 2 * n);
cnt = 1;
yy[cnt] = Y[0];
for (i = 1; i < 2 * n; i++)
{
if (fabs(Y[i] - Y[i - 1]) > eps) yy[++cnt] = Y[i];
}
//建树
build(1, cnt - 1, 1);
//把矩形拆成上下两边线段并换Y轴排序
for (i = 0; i < n; i++)
{
Edge(i * 2, sq[i].x1, sq[i].y1, sq[i].y2, 1);
Edge(i * 2 + 1, sq[i].x2, sq[i].y1, sq[i].y2, -1);
}
sort(e, e + 2 * n, cmp);
//计算面积
double ans = 0;
update(e[0].l, e[0].r - 1, e[0].mark, 1, cnt, 1);
for (i = 1; i < 2 * n; i++)
{
ans += sum[1] * (e[i].h - e[i - 1].h);
update(e[i].l, e[i].r - 1, e[i].mark, 1, cnt, 1);
}
cout << "Test case #" << kase << endl;
printf("Total explored area: %.2lf\n\n", ans);
}
}