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起码不会留下遗憾

保持冷静地快速敲出代码,这就是我接下来训练的目标吧

posted @ 2017-05-15 22:24  Drenight  阅读(125)  评论(0编辑  收藏  举报