hdu 1542 Atlantis 线段树+矩形面积并+离散化点

来源:互联网 发布:数据库日志分析工具 编辑:程序博客网 时间:2024/06/05 20:58
//根据几篇的代码修改了,自己好看懂点,haha
#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>using namespace std;struct node{    int l,r,cov;    double len;//cov是覆盖情况,len表示覆盖的长度}e[222*4];struct line{//平行于y轴的线段    double x,up,down;    int flag;//1表示矩阵左边,-1是右边}f[222];int cmp(line a,line b){    return a.x<b.x;}double y[222];void build(int a,int b,int c)//建线段树{    e[c].l=a;    e[c].r=b;    e[c].len=0;    e[c].cov=0;    if(a==b)        return;    int mid=(a+b)/2;    build(a,mid,2*c);    build(mid+1,b,2*c+1);}void update(int a,int b,int c,int flag)//修改覆盖情况cov,以及计算,{    if(a==e[c].l&&b==e[c].r)    {        if(flag==1)//cov不可能出现负数,因而可以直接判断        {            e[c].cov++;            e[c].len=y[b+1]-y[a];        }        else        {            e[c].cov--;            if(e[c].cov==0)            {                if(e[c].l==e[c].r)//叶结点                    e[c].len=0;                else                    e[c].len=e[2*c].len+e[2*c+1].len;            }        }        return;    }    int mid=(e[c].l+e[c].r)/2;    if(b<=mid)        update(a,b,2*c,flag);    else if(a>mid)        update(a,b,2*c+1,flag);    else    {        update(a,mid,2*c,flag);        update(mid+1,b,2*c+1,flag);    }    if(e[c].cov==0)        e[c].len=e[2*c].len+e[2*c+1].len;}int binary(double a[],int l,int r,double x) //二分查找x,并返回为序号   O(logN){    int mid;    while(l<=r)              {        mid = (l+r)>>1;        if(x < a[mid])            r = mid -1;        else        {            if(x > a[mid])                l = mid +1;            else                return mid;        }    }}int main(){    int n,tt=0;    while(scanf("%d",&n)!=EOF)    {        if(n==0)            break;        int i,j,k,t=0;        double x1,y1,x2,y2;        for(i=0;i<n;i++)        {            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            y[t]=y1;f[t].x=x1;f[t].up=y2;f[t].down=y1;f[t++].flag=1;            y[t]=y2;f[t].x=x2;f[t].up=y2;f[t].down=y1;f[t++].flag=-1;        }        sort(y,y+t);//将y1和y2的值离散化成0到t-1的值        sort(f,f+t,cmp);//用结构体数组f记录每条平行于y轴的线段        build(0,t-1,1);        double ans=0;        for(i=0;i<t;i++)        {            if(i!=0)                ans+=(f[i].x-f[i-1].x)*e[1].len;            int l=binary(y,0,t-1,f[i].down);//二分查找离散化对应值            int r=binary(y,0,t-1,f[i].up)-1;//线段长度,由于线段树处理的是点,所以每点表示y[i+1]-y[i]段,所以线段最后点要-1            update(l,r,1,f[i].flag);        }        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++tt,ans);    }    return 0;}/*举例:数据210 10 20 2015 15 25 25.50无限延长所有平行于Y轴的线,可得到总面积就是三个矩形((10,10),(15,20)),((15,10)(20,25.5)),((20,15),(25,25.5))面积之和离散化各点的纵坐标并排序,得到y[0]=10,y[1]=15,y[2]=20,y[3]=25.5;构建0到3的线段树,其中cov是覆盖情况。从横坐标小的开始枚举所有平行于y轴的线段,如果是矩形左边就cov+1,否则cov-1这样我们可以知道cov不为0的就是上述三个矩形的宽,长就是两个两个横坐标的差*//*转载原理:【题意】:线段树经典应用,求矩形并的面积【分析】:第一道矩形几何题,主要是练习线段树来的 求矩形的并,由于矩形的位置可以多变,因此矩形的面积一下子不好求这个时候,可以采用“分割”的思想,即把整块的矩形面积分割成几个小矩形的面积,然后求和就行了这里我们可以这样做,把每个矩形投影到 y 坐标轴上来然后我们可以枚举矩形的 x 坐标,然后检测当前相邻 x 坐标上 y 方向的合法长度,两种相乘就是面积 然后关键就是如何用线段树来维护那个 “合法长度”可以这样来搞线段树的节点这样定义struct node { int left,right,cov; double len; }cov 表示当前节点区间是否被覆盖,len 是当前区间的合法长度 然后我们通过“扫描线”的方法来进行扫描枚举 x 的竖边,矩形的左边那条竖边就是入边,右边那条就是出边了然后把所有这些竖边按照 x 坐标递增排序,每次进行插入操作由于坐标不一定为整数,因此需要进行离散化处理每次插入时如果当前区间被完全覆盖,那么就要对 cov 域进行更新入边 +1 出边 -1更新完毕后判断当前节点的 cov 域是否大于 0如果大于 0,那么当前节点的 len 域就是节点所覆盖的区间否则如果是叶子节点,则 len=0如果内部节点,则 len=左右儿子的 len 之和转自---------http://blog.sina.com.cn/s/blog_88705ca20100ufl0.html*/

原创粉丝点击