UVA1492 LA5694 线段树扫描线(矩形面积合并)

我们考虑 每个新机器往右放的起始点(1*1的块)
那么我们只要求出哪些位置不可以放就可以了,比如说 3*3 的矩阵 新机器长为2  旧机器在2 2 那么 1 1这个点就不可以放新机器(考虑机器往右放的起始点)
再考虑右边界,右边界左边m-1个位置也不可以放
再考虑往下放的起始点,同理了
综上我们只要分别求出 哪些点不可以放 再用所有点减去就可以了
其实这就转化成了求矩形面积合并的问题了
注意特判m=1 横着放竖着放重复计算了

线段树实现矩形面积合并时还是要注意一些细节,每个节点储存的是这个点到右边那个点的距离
#include <bits/stdc++.h>

using namespace std;
const int maxn=2e5+10;
typedef long long ll;
ll w,h,n,m;
struct data
{
    ll x1,x2,y;
    int flag;
} a[maxn<<2],b[maxn<<2];
ll hasha[maxn],hashb[maxn];
ll sum[maxn<<2];
ll col[maxn<<2],flaga[maxn],flagb[maxn];
inline bool cmp(data a,data b)
{
    return a.y<b.y;
}
void pushup(ll s,ll l,ll r)
{
    if(col[s]) sum[s]=hasha[r+1]-hasha[l];
    else if(l==r) sum[s]=0;
    else
    {
        sum[s]=sum[s*2]+sum[s*2+1];
    }
}
void update(ll L,ll R,ll l,ll r,ll flag,ll s)
{
    if(L<=l&&R>=r)
    {
        col[s]+=flag;
        pushup(s,l,r);
        return ;
    }
    ll m=(l+r)/2;
    if(L<=m)
    {
        update(L,R,l,m,flag,s*2);
    }
    if(R>m)
    {
        update(L,R,m+1,r,flag,s*2+1);
    }
    pushup(s,l,r);
}
int main()
{
    while(~scanf("%lld%lld%lld%lld",&w,&h,&n,&m))
    {
        for(int i = 1; i <= n; ++i)
        {
            ll xx1,yy1,xx2,yy2;
            scanf("%lld%lld%lld%lld",&xx1,&yy1,&xx2,&yy2);
            a[i*2].x1=a[i*2-1].x1=xx1-m+1>0?xx1-m+1:1;
            a[i*2].x2=a[i*2-1].x2=xx2+1;
            a[i*2-1].flag=1;
            a[i*2].flag=-1;
            hasha[i*2-1]=a[i*2-1].x1;
            hasha[2*i]=a[i*2].x2;
            a[i*2-1].y=yy1;
            a[i*2].y=yy2+1;
            b[i*2].x1=b[i*2-1].x1=yy1-m+1>0?yy1-m+1:1;
            b[i*2].x2=b[i*2-1].x2=yy2+1;
            b[i*2-1].y=xx1;
            b[i*2].y=xx2+1;
            hashb[i*2-1]=b[i*2-1].x1;
            hashb[2*i]=b[i*2].x2;
            b[i*2-1].flag=1;
            b[i*2].flag=-1;
        }
        memset(col,0,sizeof col);
        memset(sum,0,sizeof sum);
        a[2*n+2].x1=a[2*n+1].x1=w-m+2>0?w-m+2:1;
        a[2*n+1].flag=1;
        a[2*n+2].flag=-1;
        a[2*n+2].x2=a[2*n+1].x2=w+1;
        a[2*n+1].y=1;
        a[2*n+2].y=h+1;
        hasha[2*n+1]=a[n*2+1].x1;
        hasha[2*n+2]=a[n*2+2].x2;
        sort(a+1,a+2*n+3,cmp);
        sort(hasha+1,hasha+2*n+3);
        ll sz=unique(hasha+1,hasha+2*n+3)-hasha;
        long long ans=0;
        for(ll i = 1; i <= 2*n+2; ++i)
        {
            ll l=lower_bound(hasha+1,hasha+sz,a[i].x1)-hasha;
            ll r=lower_bound(hasha+1,hasha+sz,a[i].x2)-hasha-1;
            if(r>=l) update(l,r,1,sz-1,a[i].flag,1);
            ans+=sum[1]*(a[i+1].y-a[i].y);
        }
        for(ll i = 1; i <= 2*n+2; ++i)
        {
            hasha[i]=hashb[i];
            a[i]=b[i];
        }
        a[2*n+2].x1=a[2*n+1].x1=h-m+2>0?h-m+2:1;
        a[2*n+2].x2=a[2*n+1].x2=h+1;
        a[2*n+1].y=1;
        a[2*n+2].y=w+1;
        a[2*n+1].flag=1;
        a[2*n+2].flag=-1;
        hasha[2*n+1]=a[n*2+1].x1;
        hasha[2*n+2]=a[n*2+2].x2;
        memset(col,0,sizeof col);
        memset(sum,0,sizeof sum);
        sort(a+1,a+2*n+3,cmp);
        sort(hasha+1,hasha+2*n+3);
        sz=unique(hasha+1,hasha+2*n+3)-hasha;
        for(int i = 1; i <= 2*n+2; ++i)
        {
            ll l=lower_bound(hasha+1,hasha+sz,a[i].x1)-hasha;
            ll r=lower_bound(hasha+1,hasha+sz,a[i].x2)-hasha-1;
            if(r>=l) update(l,r,1,sz-1,a[i].flag,1);
            ans+=sum[1]*(a[i+1].y-a[i].y);
        }
        ans=(long long)w*h*2-ans;
        if(m==1) ans/=2;
        cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值