HDU 4419 Colorful Rectangle 线段树 扫描线 矩形面积并 容斥原理
感谢YB,CQ。
用线段树算出7种不同颜色的矩形面积并集,然后容斥原理分别算出每块单独颜色的面积。
这里的线段树写法比较特殊,只需要修改操作,查询的结果在1那个节点那里,重点是pushUp,因为这里扫描线求矩形面积并是一种特殊区间修改(保证随时都大于0,相同区间至少会有2个,一个下边,一个上边,所以可以不用像一般的区间修改线段树一样带Lazy标记的同时需要pushDown),标记当前区间是否存在,不存在就访问左右孩子。
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 #include <iostream>
5 #define lld "%I64d\n"
6 using namespace std;
7 typedef long long ll;
8 const int maxn = 1e4 + 4;
9 int T, n, sc, xc, X[maxn << 1], a[maxn << 1];
10 struct segment {
11 int l, r, h, c, d, lid, rid;
12 segment(int l = 0, int r = 0, int h = 0, int c = 0, int d = 0) : l(l), r(r), h(h), c(c), d(d) {}
13 }segs[maxn << 1];
14 #define m ((l + r) >> 1)
15 #define lc o << 1
16 #define rc lc | 1
17 int ql, qr, val, sum[maxn << 3], mark[maxn << 3];
18 inline void pushUp(int o, int l, int r) {
19 if (mark[o])
20 sum[o] = X[r] - X[l - 1];
21 else if (l == r)
22 sum[o] = 0;
23 else
24 sum[o] = sum[lc] + sum[rc];
25 }
26 inline void modify(int o, int l, int r) {
27 if (ql <= l && r <= qr) {
28 mark[o] += val;
29 pushUp(o, l, r);
30 } else {
31 if (ql <= m)
32 modify(lc, l, m);
33 if (m < qr)
34 modify(rc, m + 1, r);
35 pushUp(o, l, r);
36 }
37 }
38 int main() {
39 scanf("%d", &T);
40 for (int Tc = 1; Tc <= T; ++Tc) {
41 scanf("%d", &n);
42 sc = xc = 0;
43 for (int i = 0; i < n; ++i) {
44 int x1, x2, y1, y2, c;
45 char color[4];
46 scanf("%s%d%d%d%d", color, &x1, &y1, &x2, &y2);
47 switch (color[0]) {
48 case 'R' : c = 1; break;
49 case 'G' : c = 2; break;
50 case 'B' : c = 4; break;
51 }
52 segs[sc++] = segment(x1, x2, y1, c, 1);
53 segs[sc++] = segment(x1, x2, y2, c, -1);
54 X[xc++] = x1;
55 X[xc++] = x2;
56 a[sc - 1] = sc - 1;
57 a[sc - 2] = sc - 2;
58 }
59 sort(a, a + sc, [](int x, int y) { return segs[x].h < segs[y].h; } );
60 sort(X, X + xc);
61 xc = unique(X, X + xc) - X;
62 for (int i = 0; i < sc; ++i) {
63 segment &s = segs[i];
64 s.lid = lower_bound(X, X + xc, s.l) - X + 1;
65 s.rid = lower_bound(X, X + xc, s.r) - X;
66 }
67 ll _[8];
68 memset(_, 0, sizeof(_));
69 for (int st = 1; st < 8; ++st) {
70 memset(sum , 0, sizeof(int) * (xc << 2));
71 memset(mark , 0, sizeof(int) * (xc << 2));
72 ll &ans = _[st];
73 int last = -1;
74 for (int i = 0; i < sc; ++i) {
75 segment &s = segs[a[i]];
76 if (st & s.c) {
77 if (last != -1)
78 ans += (ll)sum[1] * (s.h - segs[last].h);
79 ql = s.lid, qr = s.rid, val = s.d;
80 modify(1, 1, xc - 1);
81 last = a[i];
82 }
83 }
84 }
85 printf("Case %d:\n", Tc);
86 printf(lld, _[7] - _[6]);
87 printf(lld, _[7] - _[5]);
88 printf(lld, _[7] - _[3]);
89 printf(lld, _[5] - _[4] + _[6] - _[7]);
90 printf(lld, _[3] - _[2] + _[6] - _[7]);
91 printf(lld, _[3] - _[1] + _[5] - _[7]);
92 printf(lld, _[1] + _[2] - _[3] + _[4] - _[5] - _[6] + _[7]);
93 }
94 return 0;
95 }