推荐阅读这篇文章
这里仅根据上述文章进行一些补充。主要是注意这里线段树点的意义变成了“边”。比如+-----+-----+,看作3个点abc和两条边e1和e2,那么线段树中点a代表e1,点b代表e2。那么我们在算cover(想象成染黑)的时候,将(a,b,c)这一段染黑的时候,其实只需要染线段树中的a和b点即可!这里解释了,为什么染[l,r]的时候,实际上染的是[l, r - 1]。
但是,push_up的时候,线段树中的l,r对应实际点的l和r-1,所以要补上个1,这里解释的是为什么if(cover[rt]) seg[rt] = x[r + 1] - x[l];
最终代码:
#include <bits/stdc++.h> using namespace std; const int maxN=2e2+5; int N, M, K, cas; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define rch rt<<1 #define lch rt<<1|1 int cov[maxN<<2]; double T[maxN<<2], x[maxN]; vector<double> v; struct Line { double l, r, h; int fg; Line(double a=0, double b=0, double c=0, int d=1): l(a), r(b), h(c), fg(d){} bool operator < (const Line &s2) const {return h < s2.h;} }; vector<Line> ln; void push_up(int l, int r, int rt) { if (cov[rt]) T[rt] = v[r + 1] - v[l]; else if (l == r) T[rt] = 0; else T[rt] = T[lch] + T[rch]; } void update(int L, int R, int f, int l, int r, int rt) { if (L <= l && r <= R) { cov[rt] += f; push_up(l, r, rt); return; } int m = (l + r) / 2; if (L <= m) update(L, R, f, lson); if (R > m) update(L, R, f, rson); push_up(l, r, rt); } int main () { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif cas = 1; while (~scanf("%d", &N) && N) { v.clear(), ln.clear(); memset(cov, 0, sizeof cov), memset(T, 0, sizeof T); double x1, y1, x2, y2; for (int i = 0; i < N; ++i) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); v.push_back(x1), v.push_back(x2); ln.push_back(Line(x1, x2, y1, 1)); ln.push_back(Line(x1, x2, y2, -1)); } sort(v.begin(), v.end()), sort(ln.begin(), ln.end()); v.erase(unique(v.begin(), v.end()), v.end()); double ans = 0; for (int i = 0; i < (int)ln.size() - 1; ++i) { int L = lower_bound(v.begin(), v.end(), ln[i].l) - v.begin(); int R = lower_bound(v.begin(), v.end(), ln[i].r) - v.begin(); if (R > L) update(L, R - 1, ln[i].fg, 0, v.size() - 1, 1); ans += T[1] * (ln[i + 1].h - ln[i].h); } printf("Test case #%d Total explored area: %.2lf ", cas++, ans); } return 0; }