codevs 3044 线段树+离散化+扫描线 (矩形面积并



链接:戳这里


3044 矩形面积求并
 时间限制: 1 s
 空间限制: 256000 KB
 题目等级 : 钻石 Diamond
 题解
题目描述 Description
输入n个矩形,求他们总共占地面积(也就是求一下面积的并)

输入描述 Input Description
可能有多组数据,读到n=0为止(不超过15组)

每组数据第一行一个数n,表示矩形个数(n<=100)

接下来n行每行4个实数x1,y1,x2,y1(0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000),表示矩形的左下角坐标和右上角坐标

输出描述 Output Description
每组数据输出一行表示答案

样例输入 Sample Input
2
10 10 20 20
15 15 25 25.5
0
样例输出 Sample Output
180.00


思路:

具体的还是看之前写的博客吧


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int n;
struct Line{
    double x1,x2,y;
    int f;
    Line(double x1=0,double x2=0,double y=0,int f=0):x1(x1),x2(x2),y(y),f(f){}
    bool operator < (const Line &a)const{
        if(y==a.y) return f>a.f;
        return y<a.y;
    }
}L[1010];
double X[1010];
int tr[4010];
double sum[4010];
void build(int root,int l,int r){
    if(l==r) {
        tr[root]=0;
        sum[root]=0;
        return ;
    }
    int mid=(l+r)/2;
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
}
void pushup(int root,int l,int r){
    if(tr[root]) sum[root]=X[r+1]-X[l];
    else if(l==r) sum[root]=0;
    else sum[root]=sum[root*2]+sum[root*2+1];
}
void update(int root,int l,int r,int x,int y,int v){
    if(x<=l && y>=r){
        tr[root]+=v;
        pushup(root,l,r);
        return ;
    }
    int mid=(l+r)/2;
    if(y<=mid) update(root*2,l,mid,x,y,v);
    else if(x>mid) update(root*2+1,mid+1,r,x,y,v);
    else {
        update(root*2,l,mid,x,mid,v);
        update(root*2+1,mid+1,r,mid+1,y,v);
    }
    pushup(root,l,r);
}
int main(){
    double x1,x2,y1,y2;
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        int m=0;
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            L[++m]=Line(x1,x2,y1,1);
            X[m]=x1;
            L[++m]=Line(x1,x2,y2,-1);
            X[m]=x2;
        }
        sort(L+1,L+m+1);
        sort(X+1,X+m+1);
        int cnt=unique(X+1,X+m+1)-(X+1);
        build(1,1,cnt);
        int l=lower_bound(X+1,X+cnt+1,L[1].x1)-X;
        int r=lower_bound(X+1,X+cnt+1,L[1].x2)-X-1;
        update(1,1,cnt,l,r,L[1].f);
        double ans=0;
        for(int i=2;i<=m;i++){
            ans+=(L[i].y-L[i-1].y)*sum[1];
            l=lower_bound(X+1,X+cnt+1,L[i].x1)-X;
            r=lower_bound(X+1,X+cnt+1,L[i].x2)-X-1;
            if(r>=l) update(1,1,cnt,l,r,L[i].f);
        }
        printf("%.2f\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值