Atlantis HDU - 1542线段树/扫描线/面积并
给出一堆矩形的左下右上坐标,问矩形面积并
扫描线的本质就是把图形分层,每层的边界就是一条“扫描线”
这里的做法是把图形按照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起码不会留下遗憾
保持冷静地快速敲出代码,这就是我接下来训练的目标吧