## 覆盖的面积 HDU - 1255(扫描线进阶)

覆盖的面积 HDU - 1255(扫描线进阶)

//#pragma GCC optimize(3,"Ofast","inline")
//#include<unordered_map>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<vector>
#include<stack>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f;
int mod=1000000007;
const int N=2e3+10;
double v[N];
double ans;
struct L
{
    double x,y1,y2;
    int state;
} line[N];
struct node
{
    double l,r;
    int cover;
    double len,len2;//(len2:本题精髓)储存的是覆盖cover两次以上的长度。
} p[N<<3];
int ls(int k)
{
    return k<<1;
}
int rs(int k)
{
    return k<<1|1;
}
bool cmp(L a,L b)
{
    return a.x<b.x;
}
void pushup(int k)
{
    if(p[k].cover)p[k].len=p[k].r-p[k].l,p[k].len2=p[ls(k)].len+p[rs(k)].len;//如果这一段区间被cover,我们就取他左右儿子被cover的长度。
    else p[k].len=p[ls(k)].len+p[rs(k)].len,p[k].len2=p[ls(k)].len2+p[rs(k)].len2;//如果这一段区间没有被覆盖,就取左右儿子的被cover两次的长度。
    if(p[k].cover>1)p[k].len2=p[k].r-p[k].l;//如果本层cover两次以上,就取这一层的长度。
    else if(p[k].l==p[k].r)p[k].len2=0;//如果左右相等,长度就是0。
    		//这是求一层的面积的pushup
    		//if(p[k].cover)p[k].len=p[k].r-p[k].l;
           //else p[k].len=p[ls(k)].len+p[rs(k)].len;

}
void build(int l,int r,int k)
{
    p[k].l=v[l];
    p[k].r=v[r];
    if(r-l<=1)return ;
    int mid=(l+r)/2;
    build(l,mid,ls(k));
    build(mid,r,rs(k));
}
void modify(double x,double y,int z,int k)
{
    double l=p[k].l,r=p[k].r;
    if(x<=l&&r<=y)
    {
        p[k].cover+=z;
        pushup(k);
        return ;
    }
    if(x<p[ls(k)].r)modify(x,y,z,ls(k));
    if(y>p[rs(k)].l)modify(x,y,z,rs(k));
    pushup(k);
}
int main()
{
    int n;
    int zhl;
    scanf("%d",&zhl);
    while(zhl--)
    {
        scanf("%d",&n);
        double x1,x2,y1,y2;
        ans=0.0;
        for(int i=1;i<=2*n;i++)
        {
            v[i]=0.0;
            p[i].l=p[i].r=p[i].len=0.0;
            line[i].x=line[i].y1=line[i].y2=0.0;
        }
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            if(x1>x2)swap(x1,x2);
            if(y1>y2)swap(y1,y2);
            line[i].x=x1;
            line[i+n].x=x2;
            line[i].y1=line[i+n].y1=y1;
            line[i].y2=line[i+n].y2=y2;
            line[i].state=1;
            line[i+n].state=-1;
            v[i]=y1;
            v[i+n]=y2;
        }
        sort(v+1,v+2*n+1);
        sort(line+1,line+2*n+1,cmp);
        build(1,n*2,1);
        for(int i=1; i<=n*2; i++)
        {
            ans+=p[1].len2*(line[i].x-line[i-1].x);
            modify(line[i].y1,line[i].y2,line[i].state,1);
        }
        printf("%.2f\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值