hdu1542 Atlantis //扫描线

http://acm.hdu.edu.cn/showproblem.php?pid=1542

题意:求矩形的并面积

思路:扫描线

扫描线:把每一条平行于y轴的边,打上标记,矩形左边为正,右边为负。沿着x轴从左往右扫。离散化y轴,缩区间为点。在线段树上维护y轴。虽然是区间加操作,但是因为区间减时,必然是已经加过的值,在pushUp的地方修改一下就不需要pushDown了。

扫描线是真·区间操作,返回的时候 l+1==r

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const LL mod = 1e9+7;
const int MX = 1e5+5;
struct no{double x,uy,dy;int ior;};
bool operator<(const no &x,const no &y) {return x.x<y.x;}
vector<no>line;
vector<double>v;
int cover[MX];
double le[MX];
void pushUp(int l,int r,int rt){
    if(cover[rt]) le[rt]=v[r]-v[l];//可能覆盖之前的
    else if(l+1==r)le[rt]=0;//叶子节点
    else le[rt]=le[rt<<1]+le[rt<<1|1]; //没有标记了,由儿子得到
}
void update(int L,int R,int io,int l,int r,int rt){
    if(l>=L&&r<=R) {
        cover[rt]+=io;pushUp(l,r,rt);return ;
    }
    if(l+1==r)return ;  //到叶子节点,区间长度为2,必须返回
    int m=(l+r)>>1;
    if(L<=m) update(L,R,io,l,m,rt<<1);
    if(R>=m) update(L,R,io,m,r,rt<<1|1);//这里不再是m+1,因为要进入类似[1,2][2,3]的叶子节点
    pushUp(l,r,rt);
}
int main(){
    int n,casen=0;
    while(cin>>n){
        if(n==0)break;
        line.clear(),v.clear();
       for(int i=1;i<=n;i++){
            cover[i]=le[i]=0;
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            v.push_back(y1),v.push_back(y2);
            line.push_back(no{x1,y2,y1,1});
            line.push_back(no{x2,y2,y1,-1});
       }
       sort(line.begin(),line.end());
       sort(v.begin(),v.end());//离散化
       v.erase(unique(v.begin(),v.end()),v.end());
       double ans=0;
       for(int i=0;i<(int)line.size();i++){
            if(i>0) ans+=le[1]*(line[i].x-line[i-1].x);
            int yl=lower_bound(v.begin(),v.end(),line[i].dy)-v.begin();
            int yr=lower_bound(v.begin(),v.end(),line[i].uy)-v.begin();
            update(yl,yr,line[i].ior,0,(int)v.size()-1,1);
       }
       printf("Test case #%d\nTotal explored area: %.2f\n\n",++casen,ans);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值