给出一堆矩形的左下右上坐标,问矩形面积并
扫描线的本质就是把图形分层,每层的边界就是一条“扫描线”
这里的做法是把图形按照y坐标分成一条条等高的长条,
让长条不断加入我们的图形,即扫描的过程
{
对于每一个长条,它对图形的影响取决于它的长度,它的高度还有它是组合图的入边还是出边(取决于我们扫的方向,这里从下往上扫)
那么我们维护的信息就是这个时间点,x轴上被覆盖的总面积,
这个数据的维护用到了线段树,
首先离散化x轴上所有出现的坐标
如果这个扫描线是入边,那么对应区间的【完全覆盖次数】+1,反之-1,这是区间修改
pushup过程中,
1如果这个节点被完全覆盖,那么向上传递这个区间的长度,
2否则如果是叶子节点,上传0;
3否则向上传递子节点覆盖的总长度,这里注意,整个过程中不需要pushdown操作,所以我们把1,3分成两种情况
}
这条扫描线的信息更新完毕,我们就需要把这条扫描线到下一条扫描线的距离×总区间覆盖长度的值加进最后的答案
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=210;
struct Node{
double l,r,h;
int d;
Node(){};
Node(double a,double b,double c,int d):l(a),r(b),h(c),d(d){}
bool operator<(const Node &b)const{
return h<b.h;
}
}node[maxn];
struct st{
int cover;
double sum;
}ST[maxn<<2];
double X[maxn];
void pushup(int l,int r,int rt){
if(ST[rt].cover)ST[rt].sum=X[r+1]-X[l];
else if(l==r)ST[rt].sum=0;
else ST[rt].sum=ST[rt<<1].sum+ST[rt<<1|1].sum;
}
void build(int l,int r,int rt){
if(l==r){
ST[rt].cover=0;
ST[rt].sum=0;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(l,r,rt);
}
void update(int a,int b,int c,int l,int r,int rt){
if(a<=l&&b>=r){
ST[rt].cover+=c;
pushup(l,r,rt);
return;
}
int m=(l+r)>>1;
if(a<=m)update(a,b,c,l,m,rt<<1);
if(b>m)update(a,b,c,m+1,r,rt<<1|1);
pushup(l,r,rt);
}
int main(){
int n;
int kase=0;
while(~scanf("%d",&n)&&n){
memset(node,0,sizeof(node));
memset(ST,0,sizeof(ST));
int tot=0;
for(int i=1;i<=n;i++){
double x1,y1,x2,y2;
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
X[++tot]=x1;
node[tot]=Node(x1,x2,y1,1);
X[++tot]=x2;
node[tot]=Node(x1,x2,y2,-1);
}
sort(X+1,X+tot+1);
sort(node+1,node+tot+1);
int k=1;
for(int i=2;i<=tot;i++){
if(X[i]!=X[i-1]){
X[++k]=X[i];
}
}
build(1,k-1,1);
double ans=0;
for(int i=1;i<tot;i++){
int l=lower_bound(X+1,X+1+k,node[i].l)-X;
int r=lower_bound(X+1,X+1+k,node[i].r)-X-1;
update(l,r,node[i].d,1,k-1,1);
ans+=ST[1].sum*(node[i+1].h-node[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ans);
}
}
吐槽一句,省赛真的太遗憾了,要是把题目分配优化一下结果就会好得多,
“至少你要敲一下啊”,赛后学长们是这么讲的,
没有快速打出代码的自信,我也就放过了猜出的正解,
打出代码,才有一交的机会,在最后一刻交一发,哪怕wa起码不会留下遗憾
保持冷静地快速敲出代码,这就是我接下来训练的目标吧