思路:如上图红色的区域代表旧的机器,如果把旧的机器向左延伸m-1个单位,再把最靠右的去掉,就是蓝色的部分,那么剩下的黄色每一个格子都可以以自身为左端点放一个,所以剩下的就是求矩形面面积的并。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
typedef long long LL;
int W,H,N,M,num;
int X1[maxn],Y1[maxn],X2[maxn],Y2[maxn];
int X[maxn*5];
struct seg
{
int l,r,h,c;
seg(){}
seg(int a,int b,int d,int e):l(a),r(b),h(d),c(e){}
bool operator < (const seg & a)const
{
return h<a.h;
}
}s[maxn*5];
struct IntervalTree
{
int sum[maxn<<3],cnt[maxn<<3];
void build()
{
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
}
void maintain(int o,int l,int r)
{
if(cnt[o])sum[o]=X[r+1]-X[l];
else if(l==r)sum[o]=0;
else sum[o]=sum[o<<1]+sum[o<<1|1];
}
void update(int o,int l,int r,int q1,int q2,int t)
{
if(l>r)return;
if(q1<=l&&r<=q2)
{
cnt[o]+=t;
maintain(o,l,r);
return;
}
int mid=(l+r)>>1;
if(q1<=mid)update(o<<1,l,mid,q1,q2,t);
if(q2>mid)update(o<<1|1,mid+1,r,q1,q2,t);
maintain(o,l,r);
}
}tree;
void add(int a,int b,int c,int d)
{
X[num]=a;
s[num++]=seg(a,c,b,1);
X[num]=c;
s[num++]=seg(a,c,d,-1);
}
LL solve()
{
num=0;
for(int i=1;i<=N;i++)
{
add(max(0,X1[i]-M),Y1[i]-1,X2[i],Y2[i]);
}
add(max(0,W-M+1),0,W,H);
sort(X,X+num);
sort(s,s+num);
int nx=unique(X,X+num)-X;
tree.build();
LL ans=0;
for(int i=0;i<num-1;i++)
{
int l=lower_bound(X,X+nx,s[i].l)-X;
int r=lower_bound(X,X+nx,s[i].r)-X-1;
if(l<=r)//刚开始没加这个判断,栈溢出
{
tree.update(1,0,nx-1,l,r,s[i].c);
ans+=(LL)tree.sum[1]*(s[i+1].h-s[i].h);
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d%d%d",&W,&H,&N,&M)!=EOF)
{
for(int i=1;i<=N;i++)
scanf("%d%d%d%d",&X1[i],&Y1[i],&X2[i],&Y2[i]);
LL ans=(LL)W*H-solve();
if(M==1)
{
cout<<ans<<endl;
continue;
}
swap(W,H);
for(int i=1;i<=N;i++)
{
swap(X1[i],Y1[i]);
swap(X2[i],Y2[i]);
}
ans+=(LL)W*H-solve();
cout<<ans<<endl;
}
return 0;
}
本文介绍了一种利用计算几何和区间树解决特定问题的方法。通过将旧机器向左延伸并去除最右侧部分来简化问题,进而求解剩余区域的并集面积。使用C++实现算法,包括区间的合并与查询更新。
1030

被折叠的 条评论
为什么被折叠?



