[离散化+扫描线+线段树]LightOJ 1120 - Rectangle Union

传送门:http://lightoj.com/volume_showproblem.php?problem=1120

1120 - Rectangle Union
Time Limit:2 second(s) Memory Limit:64 MB

Given some axis parallel rectangles, you have to find the union of their area. For example, see the shaded regions in the picture. Each rectangle will be denoted by four integers. They arex1, y1, x2, y2where(x1, y1)denotes the lower left corner and(x2, y2)denotes the upper right corner.

For the picture above, there are three rectangles. For the yellow rectangle the co-ordinates are (0, 2) and (3, 6). For the blue rectangle the co-ordinates are (1, 3) and (6, 7). For the green rectangle the co-ordinates are (2, 1) and (5, 4). So, the union area is (the shaded region) 31 square units.

Input

Input starts with an integerT (≤ 13), denoting the number of test cases.

Each case starts with a line containing an integern (1 ≤ n ≤ 30000). Each of the nextnlines will contain four integersx1, y1, x2, y2(0 ≤ x1, y1, x2, y2≤ 109, x1< x2, y1< y2)denoting a rectangle.

Output

For each case, print the case number and the union area.

Sample Input

Output for Sample Input

2

3

0 2 3 6

1 3 6 7

2 1 5 4

2

0 0 4 4

1 1 2 5

Case 1: 31

Case 2: 17

Notes

Dataset is huge, use faster I/O methods.

题意:很裸就矩形面积并,直接扫描线.

注意点:由于面积最大可以达到10^18次方,所以结果需要用long long,而且在中间计算时需要强制转换,否则会溢出.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 33333;
int x[MAXN<<1],t,n,sum[MAXN<<3],cnt[MAXN<<3],x_num,line_num;
unsigned __int64 ans;
struct Line{
    int l,r,h,s;
    Line(){}
    Line(int ll,int rr,int hh,int ss):l(ll),r(rr),h(hh),s(ss){}
    bool operator < (const Line &l) const{
        return h<l.h;
    }
}L[MAXN<<1];
#define lson l,m,rt<<1
#define rson m,r,rt<<1|1
void build(){
    memset(sum,0,sizeof(sum));
    memset(cnt,0,sizeof(cnt));
    x_num = line_num = 0;
    ans = 0;
}
void pushUP(int rt,int l,int r){
    if(cnt[rt]){
        sum[rt] = x[r]-x[l];
    }else{
        sum[rt] = sum[rt<<1]+sum[rt<<1|1];
    }
}
void update(int L,int R,int s,int l,int r,int rt){
    if(L<=l&&R>=r){
        cnt[rt]+=s;
        pushUP(rt,l,r);
        return;
    }
    if(l==r-1)return;
    int m = (l+r)>>1;
    if(m>L)update(L,R,s,lson);
    if(m<R)update(L,R,s,rson);
    pushUP(rt,l,r);
}
int search(int k){
    int l=0,r=x_num-1,m;
    while(l<=r){
        m = (l+r)>>1;
        if(x[m]==k)return m;
        else if(k<x[m])r = m-1;
        else l = m+1;
    }
    return -1;
}
int main(){
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        scanf("%d",&n);
        build();
        for(int i=0;i<n;i++){
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            x[x_num++] = a;
            x[x_num++] = c;
            L[line_num++] = Line(a,c,b,1);
            L[line_num++] = Line(a,c,d,-1);
        }
        sort(x,x+x_num);sort(L,L+line_num);
        int temp = 1;
        for(int i=1;i<x_num;i++)if(x[i]!=x[i-1])x[temp++]=x[i];
        x_num = temp;
        for(int i=0;i<line_num;i++){
            int l = search(L[i].l);
            int r = search(L[i].r);
            if(!i){
                update(l,r,L[i].s,0,x_num-1,1);
            }else{
                ans += (__int64)sum[1]*(L[i].h-L[i-1].h);
                update(l,r,L[i].s,0,x_num-1,1);
            }
        }
        printf("Case %d: %llu\n",cas,ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值