hdu1255 线段树+扫描线+离散化

  题意是求矩形覆盖2次以上的面积 

第一道扫面线题   看了网上一些扫描线的讲解    没怎么看懂   自己试着敲了一下  感觉还行    比较容易懂

关于扫描线的概念就不多说了 直接上题

离散化:对x轴   

线段树 :对离散后的x值

扫描线:对与x轴平行的边

注意节点的的子树     应为必须是一个区间 所有最小区间为为1-2   2-3  3-4  4-5  ·········· 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define LL(x) (x<<1)
#define RR(x) ((x<<1)|1)

struct node
{
    double y;
    int x1,x2;
    int flash;
}A[3100];
struct Node
{
    double x;
    int tt;
    int ii;
}scatter[3100];
int leap[10000];//标记节点  如果==-1说明当前节点表示的区间不是不是一样的值   否则为对应的值
int n;
double map[3100];//每个下标对应浮点型x的值
int cmp(Node a,Node b)
{
    return a.x<b.x;
}
int cmp2(Node a,Node b)
{
    if(a.ii!=b.ii) return a.ii<b.ii;
    else return a.x<b.x;
}
int cmp3(node a,node b)
{
    return a.y<b.y;
}
int update(int L,int R,int left,int right,int mark,int k)
{
    int mid=(L+R)/2;
    if(L==left&&right==R)
    {
        if(leap[mark]>=0)
        {
            leap[mark]+=k;    
        }
        else
        {
            update(L,mid,L,mid,LL(mark),k);
            update(mid,R,mid,R,RR(mark),k);
            if(leap[LL(mark)]==leap[RR(mark)]) leap[mark]=leap[LL(mark)];
        }
    }
    else
    {
        if(leap[mark]>=0)
        {
            leap[LL(mark)]=leap[mark];
            leap[RR(mark)]=leap[mark];
        }
        if(right<=mid)
        {
            update(L,mid,left,right,LL(mark),k);
        }
        else if(left>=mid)
        {
            update(mid,R,left,right,RR(mark),k);
        }
        else
        {
            update(L,mid,left,mid,LL(mark),k);
            update(mid,R,mid,right,RR(mark),k);
        }
        if(leap[LL(mark)]==leap[RR(mark)]) leap[mark]=leap[LL(mark)];
        else leap[mark]=-1;
    }
    return 0;
}
double find(int L,int R,int mark)
{
    double dis=0;
    if(leap[mark]>=2)
    {
        dis+=map[R]-map[L];
        return dis;
    }
    if(leap[mark]>=0) return 0;
    int mid=(L+R)/2;
    dis+=find(L,mid,LL(mark))+find(mid,R,RR(mark));
    return dis;
}
int main()
{
    int T,i,j,a,b;
    double x1,y1,x2,y2;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(A,0,sizeof(A));
        memset(map,0,sizeof(map));
        for(i=1;i<=2*n;i+=2)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            A[i].y=y1;
            A[i].flash=1;
            A[i+1].y=y2;
            A[i+1].flash=-1;
            scatter[i].x=x1;
            scatter[i].ii=i;
            scatter[i+1].x=x2;
            scatter[i+1].ii=i;
        }
        sort(scatter+1,scatter+2*n+1,cmp);//对x来离散   应为x值为浮点型  不能成为数组下标
        double k=-1;
        int j=0;
        for(i=1;i<=2*n;i++)
        {
            if(scatter[i].x!=k)
            {
                k=scatter[i].x;
                scatter[i].tt=++j;
                map[j]=scatter[i].x;
            }
            else scatter[i].tt=j;
        }
        sort(scatter+1,scatter+2*n+1,cmp2);
        for(i=1;i<=2*n;i+=2)
        {
            A[i].x1=scatter[i].tt;
            A[i].x2=scatter[i+1].tt;
            A[i+1].x1=scatter[i].tt;
            A[i+1].x2=scatter[i+1].tt;
        }
        sort(A+1,A+2*n+1,cmp3);//把所有与x轴平行的边按对应的y值排序
        memset(leap,0,sizeof(leap));
        double area=0;
        a=A[1].x1;
        b=A[1].x2;
        update(1,j,a,b,1,1);
        for(i=2;i<=2*n;i++)
        {
              a=A[i].x1;
              b=A[i].x2;
              area+=(A[i].y-A[i-1].y)*find(1,j,1);
              if(A[i].flash==1) update(1,j,A[i].x1,A[i].x2,1,1);
              else update(1,j,A[i].x1,A[i].x2,1,-1);
        }
        printf("%.2lf\n",area);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值