【AcWing 247. 亚特兰蒂斯】线段树扫描线

题目链接

题意:

给你n个矩形,问这些矩形所覆盖的面积是多少,如下图
在这里插入图片描述
就是两个矩形覆盖的总面积。

分析:

这个题我一开始想的时候直接没往线段树上想,因为这个是double类型的,线段树在我的认知看来都是int类型的,而且这个东西是二维的面积,怎么会和线段树有关呢qaq,但是这个题就是用线段树扫描线做出来的,具体是怎么扫描的呢,下面来看个图片。在这里插入图片描述
假如蓝色的部分是题目中给出的矩形,红色的线是对于每个x坐标画出的线,那么对于每段区间(x[i],x[i+1]),只需要找出矩形的高度即可,如x1~x2,就是两个绿色矩形的高加起来,那么这一部分的答案就是底乘高,现在咱们的当务之急就是对于每段区间,都能找到那个对应的高度,那么咱们就可以用线段树来维护每段区间的高度和,每个结构体中有l,r,len,cnt四个变量,其中len代表的是这个区间的高度,cnt代表的是这个区间被多少个矩形覆盖着,下面具体请看代码:

#include<bits/stdc++.h>
#define ll (k<<1)
#define rr (k<<1|1)
#define Mid (tr[k].r + tr[k].l >> 1)
#define Len (tr[k].r - tr[k].l + 1)
using namespace std;
const int N = 10010;
vector<double> alls;
struct node{
    double x,y1,y2;
    int k;
    bool operator<(const node&t)const{
        return x < t.x;
    }
}seg[N*2];
struct Node{
    int l,r,cnt;
    double len;
}tr[N<<3];
int n;
int find(double x){
    return lower_bound(alls.begin(),alls.end(),x) - alls.begin();
}
void pu(int k){
    if(tr[k].cnt) tr[k].len = alls[tr[k].r+1] - alls[tr[k].l];
    else if(tr[k].l == tr[k].r) tr[k].len = 0;
    else if(tr[k].cnt == 0) tr[k].len = tr[ll].len + tr[rr].len;
}
void build(int k,int l,int r){
    tr[k] = {l,r,0,0};
    if(l == r) return;
    build(ll,l,Mid);
    build(rr,Mid+1,r);
    pu(k);
}
void update(int k,int l,int r,int val){
    if(tr[k].l >= l && tr[k].r <= r){
        tr[k].cnt += val;
        pu(k);
        return;
    }
    if(l <= Mid) update(ll,l,r,val);
    if(r > Mid) update(rr,l,r,val);
    pu(k);
}
int main(){
    int T = 1;
    while(scanf("%d",&n),n){
        alls.clear();
        for(int i=0,j=0;i<n;i++){
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            seg[j++] = {x1,y1,y2,1};
            seg[j++] = {x2,y1,y2,-1};
            alls.push_back(y1);
            alls.push_back(y2);
        }
        sort(alls.begin(),alls.end());
        alls.erase(unique(alls.begin(),alls.end()),alls.end());
        build(1,0,alls.size()-2);
        double ans = 0;
        sort(seg,seg+n*2);
        for(int i=0,j=0;i<2*n;){
            if(i > 0) ans += tr[1].len * (seg[i].x - seg[i-1].x);
            j = i;
            while(i < 2*n && seg[i].x == seg[j].x) j++;
            while(i < j){
                int l = find(seg[i].y1),r = find(seg[i].y2)-1;
                update(1,l,r,seg[i].k);
                i++;
            }
        }
        printf("Test case #%d\n",T++);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波一打七~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值