HDU-1542:Atlantis(扫描线模板题)

来源:互联网 发布:笔记本风扇转速软件 编辑:程序博客网 时间:2024/06/06 04:44

题目链接:点击打开链接


题目大意

题目给你一些矩形的左下角坐标和右上角坐标,然后计算形成的新图形的面积。中间重叠的部分算作一部分。

题意解析

要用到线段树扫描线的知识,从坐标系的下面往上面一次扫,每次维护当前高度的有效线段长。然后就可以通过高度差还有效线段长计算有效面积。

代码:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#include<vector>using namespace std;struct node     //记录线段左端点右端点和当前线段高度{    double l,r,h;    int flag;       //记录当前线段为上位边和下位边    bool operator<(const node &b)      //通过线段高度对线段排序    {        return h<b.h;    }}nodes[500000];struct tree{    int l,r,mid;    int cnt;    //下位边减上位边的数    double sum;  //本节点控制区域内cnt不为0的总长度}t[500000];int n;double x[500000];void pushdown(int rt)       //从上到下维护{    if(t[rt].cnt!=-1)    {        t[rt<<1].cnt=t[rt<<1|1].cnt=t[rt].cnt;        if(t[rt].cnt)        {            t[rt<<1].sum=x[t[rt].mid+1]-x[t[rt].l];            t[rt<<1|1].sum=x[t[rt].r+1]-x[t[rt].mid+1];        }        else        {            t[rt<<1].sum=0;            t[rt<<1|1].sum=0;        }    }}void pushup(int rt)     //自上而下维护,cnt=-1代表当前区间左右儿子的上下位边数不同{    if(t[rt<<1].cnt==-1||t[rt<<1|1].cnt==-1)        t[rt].cnt=-1;    else if(t[rt<<1].cnt!=t[rt<<1|1].cnt)        t[rt].cnt=-1;    else        t[rt].cnt=t[rt<<1].cnt;    t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;    //printf("----%lf %d %lf %d\n",t[rt<<1].sum,t[rt<<1].l,t[rt<<1|1].sum,t[rt<<1|1].l);}void build(int l,int r,int rt){    if(l==r)    {        t[rt].l=t[rt].r=l;        t[rt].mid=(t[rt].l+t[rt].r)/2;        t[rt].cnt=0;        t[rt].sum=0.0;        return ;    }    int mid=(l+r)/2;    t[rt].l=l;    t[rt].r=r;    t[rt].mid=mid;    t[rt].cnt=0;    t[rt].sum=0.0;    build(l,mid,rt<<1);    build(mid+1,r,rt<<1|1);    pushup(rt);}void update(int l,int r,int flag,int rt)    //更新结果{    if(t[rt].l>=l&&t[rt].r<=r)    {        if(t[rt].cnt!=-1)        {            t[rt].cnt=t[rt].cnt+flag;            if(t[rt].cnt)                t[rt].sum=x[t[rt].r+1]-x[t[rt].l];            else                t[rt].sum=0;            return ;        }    }    pushdown(rt);    if(l<=t[rt].mid)        update(l,r,flag,rt<<1);    if(r>t[rt].mid)        update(l,r,flag,rt<<1|1);    pushup(rt);}int bin(double key,int n,double d[]){    int l=1,r=n;    while(l<=r)    {        int m=(l+r)/2;        if(d[m]==key)            return m;        else if(d[m]>key)            r=m-1;        else            l=m+1;    }    return -1;}int main(){    int kase=0;    while(scanf("%d",&n)!=EOF)    {        int gg=0;        if(n==0)            break;        for(int i=0;i<n;i++)        {            double x1,y1,x2,y2;            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            x[++gg]=x1;            nodes[gg].l=x1;            nodes[gg].r=x2;            nodes[gg].h=y1;            nodes[gg].flag=1;            x[++gg]=x2;            nodes[gg].l=x1;            nodes[gg].r=x2;            nodes[gg].h=y2;            nodes[gg].flag=-1;        }        sort(x+1,x+gg+1);        sort(nodes+1,nodes+gg+1);        int k=1;        for(int i=2;i<=gg;i++)        {            if(x[i-1]!=x[i])                x[++k]=x[i];        }        build(1,k-1,1);     //用每个节点代表一段区间        double ans=0.0;        for(int i=1;i<gg;i++)        {            int l=bin(nodes[i].l,k,x);            int r=bin(nodes[i].r,k,x)-1;            if(l<=r)                update(l,r,nodes[i].flag,1);            //printf("%lf\n",t[1].sum);            ans=ans+t[1].sum*(nodes[i+1].h-nodes[i].h);        }        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ans);    }}

原创粉丝点击