poj 1151 & hdu 1542 Atlantis(线段树,扫描线)

第一次做扫描线,这个是矩形面积并。。。。wa了好多发,才发现本应是double的数组写成了int。。。。
HH神总结的线段树专辑:https://wenku.baidu.com/view/71fc1659ba1aa8114431d97b.html
里面的例题。。。。
思路:浮点数先要离散化;然后把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用 cnt 表示该区间下边比上边多几个。比如cnt[i]=0,说明节点i所管理的区间没有被线段覆盖。。。
线段树的每个叶节点表示一条线段,不是一个点
用结构体保存线段,每条线段有两个端点的x坐标和线段的高度(y坐标)和一个标记s组成,s为1表示这条线段是矩形中下边的那条线段,s为-1表示为上边的那条线段,其余的写在图片和代码中。。。
这里写图片描述

#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct Line
{
    double l,r,h;
    int s;
    Line(){}
    Line(double a, double b, double c, int d):l(a),r(b),h(c),s(d){}
    bool operator < (const Line& b) const
    {
        return h < b.h;
    }
};

const int MAXN = 2222;
Line lines[MAXN];
double x[MAXN];
int cnt[MAXN<<2];
double sum[MAXN<<2];

int binS(int n, double val)
{
    int lb = 0;
    int ub = n-1;
    while(lb <= ub)
    {
        int mid = (lb+ub) >> 1;
        if(x[mid] > val) ub = mid-1;
        else if(x[mid] < val) lb = mid+1;
        else return mid;
    }
    return -1;
}

void pushUp(int l, int r, int rt)
{
    //区间完全被覆盖
    if(cnt[rt]) sum[rt] = x[r+1]-x[l];
    else if(l == r) sum[rt] = 0;
    //区间部分被覆盖,那就计算出子节点覆盖的长度
    else sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}

void update(int L ,int R, int c, int l, int r, int rt)
{
    if(l >= L && r <= R)
    {
        cnt[rt] += c;
        pushUp(l,r,rt);//计算当前节点覆盖的长度
        return;
    }
    int m = (l+r) >> 1;
    if(L <= m) update(L,R,c,lson);
    if(R > m) update(L,R,c,rson);
    pushUp(l,r,rt);
}

int main()
{
    ios::sync_with_stdio(false);
    int n,m,time = 0;
    double a,b,c,d;
    while(cin >> n && n)
    {
        m = 0;
        for(int i = 0; i < n; ++i)
        {
            cin >> a >> b >> c >> d;
            x[m] = a;
            lines[m++] = Line(a,c,b,1);
            x[m] = c;
            lines[m++] = Line(a,c,d,-1);
        }
        sort(x,x+m);
        sort(lines,lines+m);
        int k = unique(x,x+m) - x;
        double res = 0;
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        for(int i = 0; i < m-1; ++i)
        {
            //l表示是从左边数第几个线段
            int l = binS(k,lines[i].l);
            //binS(k,lines[i].r)表示的是线段右边的点,-1表示的就是这是第几条线段
            int r = binS(k,lines[i].r)-1;
            if(l <= r)
                update(l,r,lines[i].s,0,k-1,1);
            res += sum[1]*(lines[i+1].h-lines[i].h);
        }
        cout << "Test case #" << ++time << endl;
        cout << fixed << setprecision(2) << "Total explored area: " << res << endl << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值