线段树--求矩形并面积HDU1482

题目大意:给你几个矩形求并面积,做法:线段树

#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl;
#define x first 
#define y second
using namespace std;

typedef pair<double, double> pdd;
typedef long long ll;
const int N = 4e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n, k;
struct Line {
    double yd, yu, xx;//边的y上坐标y下坐标,横坐标。
    int d;//区分入边和出边。入边为1,出边为-1.
    bool operator < (const Line& A) {
        return xx < A.xx;
    }
    Line() {}
    Line(double _yd, double _yu, double _xx, int _d) :
        yd(_yd), yu(_yu), xx(_xx), d(_d) {}
}scan[N];//扫描线。
int tot;//扫描线数量。
int cover[N];//存放i结点对应覆盖情况的值。
double length[N];//存放区间i下的总长度。
double yy[N];//存放离散后的y的值,下标我们用lower_bound进行查找。
void pushup(int rt, int l, int r) {
    if (cover[rt]) {
        length[rt] = yy[r] - yy[l];
    }
    else if (l + 1 == r) {
        length[rt] = 0;//到了叶子结点。
    }
    else {
        length[rt] = length[rt << 1] + length[rt << 1 | 1];
    }
}
void update(int rt, int l, int r, int yl, int yr, int d) {//l  r              yl,yr为去过重的 所在的位置 
    if (yl <= l && yr >= r) {
        //说明区间全部包含在里面。
        cover[rt] += d;//根据出边入边加上相应值。
        pushup(rt, l, r);
        return;
    }
    if (l + 1 == r)return;//到了子节点。
    int mid = (l + r) >> 1;
    if (yl <= mid) {
        update(rt << 1, l, mid, yl, yr, d);
    }
    if (yr > mid) {
        update(rt << 1 | 1, mid, r, yl, yr, d);
    }
    pushup(rt, l, r);
}
void solve() {
    sort(yy + 1, yy + tot + 1);// 排序      yy存的是矩形的纵坐标
    sort(scan + 1, scan + 1 + tot);//排序   scan 存的是扫描线 排序按照  x的大小排序
    //获取去重后的边数组。
    int len = unique(yy + 1, yy + tot + 1) - (yy + 1); //去重完后矩阵的纵坐标
    fill(length, length + N, 0);//区间下的总长度初始置为0
    fill(cover, cover + N, 0);   //存放覆盖的情况        
    int yl, yr;
    double ans = 0;//累加矩形面积。
    for (int i = 1; i <= tot; ++i) {
        ans += length[1] * (scan[i].xx - scan[i - 1].xx);
        yl = lower_bound(yy + 1, yy + 1 + len, scan[i].yd) - yy;//返回第一个大于等于当前扫描线左下角纵坐标   在所有纵坐标的位置
        yr = lower_bound(yy + 1, yy + 1 + len, scan[i].yu) - yy;//返回第一个大于等于当前扫描线右上角纵坐标   在所有纵坐标的位置
        update(1, 1, len, yl, yr, scan[i].d);
    }
    printf("Test case #%d\nTotal explored area: %.2f\n\n", k, ans);
}
int main() {
    pdd a, b;
    while (~scanf("%d", &n) && n) {
        k++;
        tot = 0;
        for (int i = 0; i < n; ++i) {
            //矩形的左下角和右上角坐标。
            scanf("%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y);
            //下底扫描线和上底扫描线。
            //即给入边和出边赋值。
            scan[++tot] = Line(a.y, b.y, a.x, 1);
            yy[tot] = a.y;
            scan[++tot] = Line(a.y, b.y, b.x, -1);
            yy[tot] = b.y;
        }
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值