2017 南宁网络赛 Overlapping Rectangles (离散化+扫描线/线段树)

题目:https://nanti.jisuanke.com/t/17313

题意:

确定矩形面积。

#include<bits/stdc++.h>
using namespace std;

double x[2002],y[2002];//最多100个矩形,所以最多只有200条横线或纵线
double a[1002][4];//矩形实际坐标
bool cover[2002][2002];
const double EPS = 1e-7;

int cmp(const void * b,const  void * a){//b>a 返回1
    if(fabs(*(double* )b-*(double *)a)<EPS)return 0;
    else if(*(double* )b-*(double *)a>0)return 1;
    else return -1;
}

int main(){
    int n,i,k,j,h1,h2,v1,v2;
    while(scanf("%d",&n) != EOF){
        if(n==0) {
            printf("*\n");
            break;
        }
        for(i=0,k=0;i<n;i++,k++){
            scanf("%lf%lf%lf%lf",&a[i][0],&a[i][1],&a[i][2],&a[i][3]);
            x[k]=a[i][0],y[k]=a[i][1],x[++k]=a[i][2],y[k]=a[i][3];
        }
        qsort(x,2*n,sizeof(x[0]),cmp);
        qsort(y,2*n,sizeof(y[0]),cmp);//将横线,竖线排好序
        memset(cover,0,sizeof(cover));//初始时无覆盖区
        //对每个矩形,进行一次横纵线的扫描,覆盖范围
        //扫描线条数作为下标,离散化
        for(i=0;i<n;i++){
            k=0;
            while(fabs(x[k]-a[i][0])>EPS)k++;h1=k;
            k=0;
            while(fabs(y[k]-a[i][1])>EPS)k++;v1=k;
            k=0;
            while(fabs(x[k]-a[i][2])>EPS)k++;h2=k;
            k=0;
            while(fabs(y[k]-a[i][3])>EPS)k++;v2=k;
            //标记该矩形覆盖的区域
            for(j=h1;j<h2;j++)      //不考虑最右
                for(k=v1;k<v2;k++)  //不考虑最下
                    cover[j][k]=true;
        }
        double sum=0;
        //这时再用扫描线真实的位置计算面积,由矩形左下角的点(判断是否覆盖)及四条扫描线确定。
        for(i=0;i<2*n-1;i++)
            for(j=0;j<2*n-1;j++)
                sum+=(cover[i][j]*(x[i+1]-x[i])*(y[j+1]-y[j]));
        printf("%d\n", (int)round(sum));
    }
}

接下来用线段树做。

用扫描线位置(下标)做权值建线段树。(无需lazy标记)

(加第一条线段时更改的是第一到第二条扫描线的位置,但最后算的是底边为1到3长度的面积)


#include<bits/stdc++.h>
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define ll long long int
using namespace std;

const int maxn = 2000 + 5;
int  col[maxn << 2], n, res;
double sum[maxn << 2],X[maxn << 2];  //沿X轴从左往右扫
struct seg{
    double l,r,h;
    int f;  //下边为1,上边为-1,扫描到上边时减去这个区间
    seg() {}
    seg(double l,double r,double h,int f):l(l),r(r),h(h),f(f) {}
    bool operator < (const seg & object) const {
        return h < object.h;
    }
} S[maxn];

void pushup(int rt,int l,int r){
    if(col[rt]) sum[rt]=X[r+1]-X[l]; //r+1是右端点那条
    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 rt,int l,int r){
    if(l>=L&&r<=R){
        col[rt]+=c;
        pushup(rt,l,r);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) update(L,R,c,lson);
    if(R>mid) update(L,R,c,rson);
    pushup(rt,l,r);
}

int find(double x){
    int l=-1,r=res-1;
    while(r>=l){
        int mid=(l+r)>>1;
        if(X[mid]>=x) r=mid-1;
        else l=mid+1;
    }
    return r+1;
}
int main(){
    while(scanf("%d",&n) != EOF){
        if(n==0) {
            printf("*\n");
            break;
        }
        int cnt=0;
        for(int i=0;i<n;i++){
            double a,b,c,d;
            cin>>a>>b>>c>>d;
            S[cnt]=seg(a,c,b,1), X[cnt++]=a;
            S[cnt]=seg(a,c,d,-1),X[cnt++]=c;
        }
        sort(X,X+cnt);
        sort(S,S+cnt);
        res=unique(X,X+cnt)-X;  //扫描线去重

        memset(sum,0,sizeof(sum));
        memset(col,0,sizeof(col));
        double ans=0;
        for(int i=0;i<cnt-1;i++){
            int l=find(S[i].l);  //找下标,放入线段树,相当于离散化
            int r=find(S[i].r)-1;  //找右端点左边那条,这里不会有2个以上重叠的部分
            update(l,r,S[i].f,1,0,res-1);
            ans+=sum[1]*(S[i+1].h-S[i].h);
        }
        printf("%d\n", (int)round(ans)); //四舍五入
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值