题目链接:点击打开链接
题意:给你n个矩形, 求这n个矩形所覆盖的面积(重复覆盖算一次)
思路:我们可以考虑, 将y坐标保存并排序。 按x坐标离散化后建立线段树。 每次遇到一个矩形的下底边就将这个区间+1,表示这个区间已经被几条线段覆盖了。 遇到上边就-1, 每次更新后累加当前x坐标总区间被覆盖的长度乘以相邻两边的高度。 具体原因可以画图看看就明白了。 另外很重要的一点就是, 线段树都是维护一个点集, 但是对于边的问题就会变得很麻烦, 我们可以按照区间左端点建立线段树, 那么一个点表示的就不是点了, 而是起点在这个点的一个线段。 这样的话, 右区间就要相应的-1, 例如更新区间[1, 4], 就相当于更新标号为[1, 3]的线段。
这也是处理线段覆盖问题的通用方法。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const ld eps = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = 0x3f3f3f3f; // & 0x7FFFFFFF const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 100000 + 10; int T,n,m,kase=0,addv[maxn<<2]; double sum[maxn<<2],c[maxn]; struct node { double xl, xr, h; int id; node(double xl=0, double xr=0, double h=0, int id=0):xl(xl),xr(xr),h(h),id(id) {} bool operator < (const node& rhs) const { return h < rhs.h; } }b[maxn]; void PushUp(int l, int r, int o) { if(addv[o]) sum[o] = c[r+1] - c[l]; //当前区间被线段覆盖 else if(l == r) sum[o] = 0; // 已经到了叶子结点且没有被覆盖 else sum[o] = sum[o<<1] + sum[o<<1|1]; // 没有完全被覆盖, 但是还没到叶子结点, 从其子区间中获得信息 } void build(int l, int r, int o) { int m = (l + r) >> 1; addv[o] = 0; sum[o] = 0; if(l == r) return ; build(l, m, o<<1); build(m+1, r, o<<1|1); } void update(int L, int R, int x, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { addv[o] += x; PushUp(l, r, o); return ; } if(L <= m) update(L, R, x, l, m, o<<1); if(m < R) update(L, R, x, m+1, r, o<<1|1); PushUp(l, r, o); } double xl, xr, yl, yr; int main() { while(~scanf("%d",&n) && n) { int cnt = 0, res = 0; for(int i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&xl,&yl,&xr,&yr); b[++cnt] = node(xl, xr, yl, 1); c[++res] = xl; b[++cnt] = node(xl, xr, yr, -1); c[++res] = xr; } sort(b+1, b+cnt+1); sort(c+1, c+res+1); int m = unique(c+1, c+res+1) - c - 1; build(1, m, 1); double ans = 0; for(int i=1;i<cnt;i++) { xl = lower_bound(c+1, c+1+m, b[i].xl) - c; xr = lower_bound(c+1, c+m+1, b[i].xr) - c - 1; update(xl, xr, b[i].id, 1, m, 1); ans += (b[i+1].h - b[i].h) * sum[1]; } printf("Test case #%d\n",++kase); printf("Total explored area: %.2f\n\n",ans); } return 0; }