HDU 1542 Atlantis(线段树求矩形面积并)

题目链接:点击打开链接

题意:给你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;
}


你可能感兴趣的:(线段树,HDU,离散化,ACM-ICPC)