Hdu 4052 Adding New Machine(给你W*H大小的矩形,其中有N个地区不能使用(给出了这个地区的两个顶点的坐标即(x1,y1)和(x2,y2)),问能下多少个1*M的矩形)

传送门:Hdu 4052 Adding New Machine


题意:给你W*H大小的矩形,其中有N个地区不能使用(给出了这个地区的两个顶点的坐标即(x1,y1)和(x2,y2)),问能下多少个1*M的矩形。


思路:
因为放的新的矩形的面积是特殊的,所以我们只要先考虑行(列同理)
统计行的时候问题转化为找出多少个这样的方块(i,j),使得(i,j),(i,j+1)…(i,j+m-1)
->(x1-m+1,y1)到(x2,y2)之间的方块全都是不满足的,去掉不满足的之后剩下的全都是满足的(M=1特殊考虑)

原来的方块坐标和线段左边是不等价的,将(x1,y1)->(x1-1,y1-1)


#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

struct Point{
    int x1,y1,x2,y2;
}b[N];
int X[N*2],sumv[N*8];
int mark[N*8],L,R;//记录某个区间的下底边个数
//以横坐标作为线段(区间),对横坐标线段进行扫描
//扫描的作用是每次更新下底边总长度和下底边个数,增加新面积
struct node{
    int l,r,h;
    int d;
    bool operator <(const node& rhs) const{
        return h<rhs.h;
    }
}a[N*2];

int search(double num,int l,int r){
    while(l<=r){
        int mid=(l+r)>>1;
        if(X[mid]==num)
            return mid;
        if(X[mid]<num)
            l=mid+1;
        else
            r=mid-1;
    }
    return -1;
}

void pushup(int rt,int l,int r){
    if(mark[rt])    //表示该区间整个线段长度可以作为底边
        sumv[rt]=X[r+1]-X[l];
    else if(l==r)//叶子结点则底边长度为0(区间内线段长度为0)
        sumv[rt]=0;
    else
        sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1];
}

void update(int l,int r,int rt,int d){
    if(L<=l&&R>=r){//该区间是当前扫描线段的一部分,则该区间下底边总长以及上下底边个数差更新
        mark[rt]+=d;//更新底边相差差个数
        pushup(rt,l,r);//更新底边长
        return ;
    }
    int mid=(l+r)>>1;
    if(L<=mid)
        update(lson,d);
    if(R>mid)
        update(rson,d);
    pushup(rt,l,r);
}

int M,W,H;
long long ans;

void solve(int n){
    for(int i=1;i<=n;i++){
        a[i*2-1]=node{max(b[i].x1-M+1,0),b[i].x2,b[i].y1,1},a[i*2]=node{max(b[i].x1-M+1,0),b[i].x2,b[i].y2,-1};
        X[i*2-1]=max(b[i].x1-M+1,0),X[i*2]=b[i].x2;
    }
    ++n;
    a[n*2-1]=node{max(W-M+1,0),W,0,1},a[n*2]=node{max(W-M+1,0),W,H,-1};
    X[n*2-1]=max(W-M+1,0),X[n*2]=W;
    sort(a+1,a+2*n+1);
    sort(X+1,X+2*n+1);
    int m=unique(X+1,X+2*n+1)-X;//去重
    memset(mark,0,sizeof(mark));
    memset(sumv,0,sizeof(sumv));
    for(int i=1;i<2*n;i++){
        L=search(a[i].l,1,m),R=search(a[i].r,1,m)-1;
        if(L<=R){
            update(1,m,1,a[i].d);
            ans=ans+1LL*sumv[1]*(a[i+1].h-a[i].h);
        }
    }
}

int main(){
    int n;
    while(scanf("%d%d%d%d",&W,&H,&n,&M)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d",&b[i].x1,&b[i].y1,&b[i].x2,&b[i].y2);
            b[i].x1--,b[i].y1--;
        }
        ans=0;
        solve(n);
        if(M==1)
            printf("%lld\n",1LL*W*H-ans);
        else{
            swap(W,H);
            for(int i=1;i<=n;i++)
                swap(b[i].x1,b[i].y1),swap(b[i].x2,b[i].y2);
            solve(n);
            printf("%lld\n",1LL*2*W*H-ans);
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值