HDU1255 覆盖的面积
/*
┌───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
│Esc│ │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│ ┌┐ ┌┐ ┌┐
└───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘ └┘ └┘ └┘
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
│~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │Num│ / │ * │ - │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
│ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │ │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
│ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter │ │ 4 │ 5 │ 6 │ │
├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ ┌───┐ ├───┼───┼───┼───┤
│ Shift │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│ Shift │ │ ↑ │ │ 1 │ 2 │ 3 │ │
├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
│ Ctrl│ Win│ Alt│ Space │ Alt│ Win│Menu│Ctrl│ │ ← │ ↓ │ → │ │ 0 │ . │←─┘│
└─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
*/
放一个B站讲解扫描线的视频,【AgOHの算法胡扯】扫描线算法(点击跳转)
下面是扫描线的题目
题目链接
Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
Sample Input
2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1
Sample Output
7.63
0.00
AC代码
#include<cstdio>
#include<algorithm>
const int N = 2005;
double v[N];
struct Line {
double y, x1, x2;
int state;
Line() {}
Line(double y, double x1, double x2, int state) : y(y), x1(x1), x2(x2), state(state) {}
bool operator<(const Line &oth) { return y < oth.y; }
} line[N];
struct Node {
double l, r, len, len2;
int cover;
Node() {}
Node(double l, double r, double len, double len2, int cover) : l(l), r(r), len(len), len2(len2), cover(cover) {}
} seg[N << 3];
inline int ls(int k) { return k << 1; }
inline int rs(int k) { return k << 1 | 1; }
inline void PushUp(int k) {
if (seg[k].cover) seg[k].len = seg[k].r - seg[k].l;
else seg[k].len = seg[ls(k)].len + seg[rs(k)].len;
if (seg[k].cover >= 2) seg[k].len2 = seg[k].r - seg[k].l;
else if (seg[k].cover == 1) seg[k].len2 = seg[ls(k)].len + seg[rs(k)].len;
else seg[k].len2 = seg[ls(k)].len2 + seg[rs(k)].len2;
}
void BuildTree(int l, int r, int k = 1) {
seg[k] = Node(v[l], v[r], 0, 0, 0);
if (r - l <= 1) return;
int m = (l + r) >> 1;
BuildTree(l, m, ls(k));
BuildTree(m, r, rs(k));
}
void modify(double L, double R, int state, int k = 1) {
double l = seg[k].l, r = seg[k].r;
if (L <= l && r <= R) {
seg[k].cover += state;
PushUp(k);
return;
}
if (L < seg[ls(k)].r) modify(L, R, state, ls(k));
if (R > seg[rs(k)].l) modify(L, R, state, rs(k));
PushUp(k);
}
int main() {
int n, T;
double a, b, c, d;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
v[i] = a, v[n + i] = c;
line[i] = Line(b, a, c, 1), line[n + i] = Line(d, a, c, -1);
}
n <<= 1;
std::sort(v + 1, v + n + 1);
std::sort(line + 1, line + n + 1);
BuildTree(1, n);
double ans = 0.0;
for (int i = 1; i <= n; ++i) {
ans += seg[1].len2 * (line[i].y - line[i - 1].y);
modify(line[i].x1, line[i].x2, line[i].state);
}
printf("%.2lf\n", ans);
}
return 0;
}