UVA 1492 - Adding New Machine(矩形面积并变形)
题目链接 https://cn.vjudge.net/problem/UVA-1492
【题意】
在一个W×H的矩形方格中要放置一个1×M的物品(可以横着放也可以竖着放),但是有一些子矩形的位置已经被占用了,给你这些子矩形的信息,问你还能有多少种不同的方案去排放这个物品
【输入格式】
多组输入,每组数据第一行为4个整数W,H,N,M(W,H<=1e7, N,M<=1e5)分别代表总长度和总宽度以及子矩形的个数和要摆放的物品的尺寸,接下来N行每行4个整数x1,y1,x2,y2(1<=x1,x2<=W, 1<=y1,y2<=H)代表子矩形的左下角和右上角坐标
【输出格式】
对每组数据,输出最后可以摆放的方案数
【思路】
分别考虑横放和竖放.先考虑横放,我们可以统计出多少个点不能放然后用总面积剪掉这个不能放的点的个数就是答案,那么那些点不能放呢,首先那些子矩形里不能放,然后就是子矩形左边M-1的单位也不能放,右边界的左边M-1个单位也不能放,所以我们可以对现有的子矩形和右边界向左做长度为M-1的延伸,在对得到的所有矩形求它们的面积并即可,也就转换成了矩形面积并的问题了. 竖放同理考虑即可,但这道题代码需要注意的细节有很多,并且还要特判m=1的情况,因为m=1的时候只算横放或竖放就能算出答案了,都算的话最后结果还要除以2
#include<bits/stdc++.h>
#define node tree[id]
#define lson tree[id<<1]
#define rson tree[id<<1|1]
using namespace std;
typedef long long ll;
const int maxn=100050;
struct Edge{
int le,ri,h,flag;
Edge(int l,int r,int hh,int f):le(l),ri(r),h(hh),flag(f){}
bool operator<(const Edge& e)const{
return h<e.h;
}
};
struct Tree{
int left,right;
int cover,len;
};
int w,h,n,m;
vector<int> x,y;
vector<Edge> edgex,edgey;
Tree tree[maxn<<2];
void build(int id,int le,int ri){
node.left=le;
node.right=ri;
node.cover=0;
node.len=0;
if(le==ri) return;
int mid=(le+ri)>>1;
build(id<<1,le,mid);
build(id<<1|1,mid+1,ri);
}
void pushup(int id,int tp){
if(node.cover){
if(0==tp) node.len=x[node.right+1]-x[node.left];
else node.len=y[node.right+1]-y[node.left];
}
else if(node.left==node.right) node.len=0;
else node.len=lson.len+rson.len;
}
void update(int id,int le,int ri,int val,int tp){
if(node.left==le && node.right==ri){
node.cover+=val;
pushup(id,tp);
return;
}
int mid=(node.left+node.right)>>1;
if(ri<=mid) update(id<<1,le,ri,val,tp);
else if(le>mid) update(id<<1|1,le,ri,val,tp);
else{
update(id<<1,le,mid,val,tp);
update(id<<1|1,mid+1,ri,val,tp);
}
pushup(id,tp);
}
int main(){
while(scanf("%d%d%d%d",&w,&h,&n,&m)==4){
x.clear();y.clear();
edgex.clear();edgey.clear();
ll ans=0;
if(m>1){
x.push_back(max(1,w-m+2));
x.push_back(w+1);
edgex.push_back(Edge(max(1,w-m+2),w+1,1,1));
edgex.push_back(Edge(max(1,w-m+2),w+1,h+1,-1));
y.push_back(min(m-1,h));
y.push_back(0);
edgey.push_back(Edge(0,min(m-1,h),1,1));
edgey.push_back(Edge(0,min(m-1,h),w+1,-1));
}
for(int i=0;i<n;++i){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int xL=max(1,x1-m+1),xR=x2+1;
x.push_back(xL);
x.push_back(xR);
edgex.push_back(Edge(xL,xR,y1,1));
edgex.push_back(Edge(xL,xR,y2+1,-1));
int yL=y1-1,yR=min(h,y2+m-1);
y.push_back(yL);
y.push_back(yR);
edgey.push_back(Edge(yL,yR,x1,1));
edgey.push_back(Edge(yL,yR,x2+1,-1));
}
sort(x.begin(),x.end());
x.erase(unique(x.begin(),x.end()),x.end());
if(x.size()) build(1,0,x.size()-1);
sort(edgex.begin(),edgex.end());
for(int i=0;i<(int)edgex.size()-1;++i){
int le=lower_bound(x.begin(),x.end(),edgex[i].le)-x.begin();
int ri=lower_bound(x.begin(),x.end(),edgex[i].ri)-x.begin()-1;
update(1,le,ri,edgex[i].flag,0);
ans+=(ll)tree[1].len*(ll)(edgex[i+1].h-edgex[i].h);
}
sort(y.begin(),y.end());
y.erase(unique(y.begin(),y.end()),y.end());
if(y.size()) build(1,0,y.size()-1);
sort(edgey.begin(),edgey.end());
for(int i=0;i<(int)edgey.size()-1;++i){
int le=lower_bound(y.begin(),y.end(),edgey[i].le)-y.begin();
int ri=lower_bound(y.begin(),y.end(),edgey[i].ri)-y.begin()-1;
update(1,le,ri,edgey[i].flag,1);
ans+=(ll)tree[1].len*(ll)(edgey[i+1].h-edgey[i].h);
}
ans=2LL*(ll)w*(ll)h-ans;
if(1==m) ans>>=1;
printf("%lld\n",ans);
}
return 0;
}