POJ 1151 Atlantis

来源:互联网 发布:顶级定制晚礼服 知乎 编辑:程序博客网 时间:2024/05/16 13:46

题解在注释中,每个函数都有解释。

////  main.cpp//  Richard////  Created by 邵金杰 on 16/7/25.//  Copyright © 2016年 邵金杰. All rights reserved.//#include<iostream>#include<cstdio>#include<algorithm>using namespace std;//存放纵轴的struct line{    double x,y1,y2;    bool bleft;}line[210];double y[210];struct node{    int L,R;    node *pleft,*pright;    int cover;    double len;}tree[900];int nNodetree=0;bool operator < (const struct line &l1,const struct line &l2){    return l1.x<l2.x;}template<class F,class T>F bin_search(F s,F e,T val){    F L=s;    F R=e-1;    while(L<=R)    {        F mid=L+(R-L)/2;        if(!((*mid>val)||(*mid<val))) return mid;        else if(*mid>val) R=mid-1;        else L=mid+1;    }    return e;}int mid(node *p){    return (p->L+p->R)/2;}//建树void Buildtree(node *p,int L,int R){    p->L=L;    p->R=R;    p->len=0;    p->cover=0;    if(L==R) return ;    nNodetree++;    p->pleft=tree+nNodetree;    nNodetree++;    p->pright=tree+nNodetree;    Buildtree(p->pleft,L,mid(p));    Buildtree(p->pright,mid(p)+1,R);}//如果区间刚好在所插入范围内,那么直接把p->len=y[R+1]-y[L],为什么要R+1,因为L和R都代表区间,所以这个区间的最上面的坐标为y[L],最下面的轴是y[R+1],相减就是矩形在该区间内所占的高,前提是完全覆盖该区间的,所以p->cover++,接下来就是区间没有完美配对的情况了,那么区间会分解,这都是套路不说了,最后那句话是更新母节点的(并非是根结点),如果该结点所代表的区间不是完全被覆盖的,那么所覆盖的矩形的高就是p->len=p->pleft->len+p->pright->len;(这句话非常关键,否则根结点无法及时更新的话,会导致该条纵轴与下一条纵轴之间的矩形面积为0,导致最后答案错误);void Insert(node *p,int L,int R){    if(p->L==L&&p->R==R)    {        p->len=y[R+1]-y[L];        p->cover++;        return ;    }    if(R<=mid(p)) Insert(p->pleft,L,R);    else if(L>mid(p)) Insert(p->pright,L,R);    else{        Insert(p->pleft,L,mid(p));        Insert(p->pright,mid(p)+1,R);    }    if(p->cover==0)        p->len=p->pleft->len+p->pright->len;}//与Insert类似,如果完美配对,那么矩形之前是完美覆盖该区间的,那么现在矩形到右边的轴了,就不再覆盖了,所以p->cover--,当p->cover==0时,代表该区间已经没有完全覆盖的矩形了,如果时单个区间,那么p->len=0,如果是多个单区间组合起来的组合区间,那么p->len=p->pleft->len+p->pright->len;(因为可能有不完美覆盖该区间的矩形,但是有一部分在该区间内),接下来是区间不配对时的分解区间,最后一个if的意思也是跟新母节点,知道跟新根结点,理由在Insert函数中已经阐述过了,类似。void Delete(node *p,int L,int R){    if(p->L==L&&p->R==R)    {        p->cover--;        if(p->cover==0){            if(p->L==p->R) p->len=0;            else p->len=p->pleft->len+p->pright->len;        }        return ;    }    if(R<=mid(p)) Delete(p->pleft,L,R);    else if(L>mid(p)) Delete(p->pright,L,R);    else{        Delete(p->pleft,L,mid(p));        Delete(p->pright,mid(p)+1,R);    }    if(p->cover==0)        p->len=p->pleft->len+p->pright->len;}int main(){    int n,kase=0,yc,lc;    double x1,x2,y1,y2;    double area;    while(scanf("%d",&n)&&n)    {        area=0;        yc=0,lc=0;        for(int i=0;i<n;i++)        {            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            y[yc++]=y1;            y[yc++]=y2;            line[lc].x=x1;            line[lc].y1=y1;            line[lc].y2=y2;            line[lc].bleft=true;            lc++;            line[lc].x=x2;            line[lc].y1=y1;            line[lc].y2=y2;            line[lc].bleft=false;            lc++;        }        sort(y,y+yc);//整理横轴,然后分解区间        yc=(int)(unique(y,y+yc)-y);//一共有yc条横轴        Buildtree(tree,0,yc-1-1);//yc-1是区间数,因为区间开始是0,所以结束是yc-1-1;        sort(line,line+lc);        for(int i=0;i<lc-1;i++)        {            int L=(int)(bin_search(y,y+yc,line[i].y1)-y);            int R=(int)(bin_search(y,y+yc,line[i].y2)-y);//寻找该矩形的区间            if(line[i].bleft)                Insert(tree,L,R-1);//因为找到的是线的位置,但是插入是对区间操作的,所以区间是从L~R-1的            else                Delete(tree,L,R-1);            area+=tree[0].len*(line[i+1].x-line[i].x);//tree[0]代表的是在line[i].x与line[i+1].x之间举行的宽是多少,相乘之后就代表了在line[i].x~line[i+1].x之间的矩形面积,因为有lc-1个范围,所以每次area都要更新。        }        printf("Test case #%d\n",++kase);        printf("Total explored area: %.2f \n",area);        printf("\n");    }    return 0;}


0 0
原创粉丝点击