HDU 1255 覆盖的面积 线段树+扫描线+离散化

时空隧道


分析:
求矩形覆盖两次以上的面积…和上一题差不多…
但是计算区间被覆盖长度的时候不太一样…
当当前区间被完全覆盖两次的时候不用多说…如果只被完全覆盖一次呢?…
如果已经被完全覆盖了一次,那么子节点的被覆盖一次的长度现在就变为了当前节点被覆盖两次的长度…
当我看到我输出7.62二然而样例是7.63的时候我整个人都崩溃了…这还卡精度??然后抱着试一试的心态交了一发…A了??……….


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=1000+5;
int cas,n,cnt,tot;
double ans,mp[maxn*2];
struct M{
    double x1,x2,y,v;
    friend bool operator < (M xx,M yy){
        return xx.y<yy.y;
    }
}G[maxn*2];
struct Tree{
    int l,r,cover;
    double lenth,res,res2;
}tree[maxn*2*4];
inline void build(int l,int r,int tr){
    tree[tr].l=l,tree[tr].r=r,tree[tr].lenth=mp[r]-mp[l],tree[tr].cover=0,tree[tr].res=tree[tr].res2=0;
    if(l+1==r)
        return;
    int mid=(l+r)>>1;
    build(l,mid,tr<<1),build(mid,r,tr<<1|1);
}
inline void change(int l,int r,int val,int tr){
    if(tree[tr].l==l&&tree[tr].r==r){
        tree[tr].cover+=val;
        if(tree[tr].cover>=2)
            tree[tr].res=tree[tr].res2=tree[tr].lenth;
        else if(tree[tr].cover==1){
            tree[tr].res2=tree[tr].lenth;
            if(tree[tr].l+1==tree[tr].r)
                tree[tr].res=0;
            else
                tree[tr].res=tree[tr<<1].res2+tree[tr<<1|1].res2;
        }
        else{
            if(tree[tr].l+1==tree[tr].r)
                tree[tr].res=tree[tr].res2=0;
            else
                tree[tr].res2=tree[tr<<1].res2+tree[tr<<1|1].res2,
                tree[tr].res=tree[tr<<1].res+tree[tr<<1|1].res;
        }
        return;
    }
    int mid=(tree[tr].l+tree[tr].r)>>1;
    if(r<=mid)
        change(l,r,val,tr<<1);
    else if(l>=mid)
        change(l,r,val,tr<<1|1);
    else
        change(l,mid,val,tr<<1),change(mid,r,val,tr<<1|1);
    if(tree[tr].cover>=2)
        tree[tr].res=tree[tr].res2=tree[tr].lenth;
    else if(tree[tr].cover==1){
        tree[tr].res2=tree[tr].lenth;
        if(tree[tr].l+1==tree[tr].r)
            tree[tr].res=0;
        else
            tree[tr].res=tree[tr<<1].res2+tree[tr<<1|1].res2;
    }
    else{
        if(tree[tr].l+1==tree[tr].r)
            tree[tr].res=tree[tr].res2=0;
        else
            tree[tr].res2=tree[tr<<1].res2+tree[tr<<1|1].res2,
            tree[tr].res=tree[tr<<1].res+tree[tr<<1|1].res;
    }
}
signed main(void){
    scanf("%d",&cas);
    double x1,y1,x2,y2;
    while(cas--){tot=cnt=0;
        scanf("%d",&n);ans=0;
        for(int i=1;i<=n;i++)   
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2),
            G[++tot].x1=x1,G[tot].x2=x2,G[tot].y=y1,G[tot].v=1,
            G[++tot].x1=x1,G[tot].x2=x2,G[tot].y=y2,G[tot].v=-1,
            mp[++cnt]=x1,mp[++cnt]=x2;
        sort(G+1,G+tot+1),sort(mp+1,mp+cnt+1);
        int len=unique(mp+1,mp+cnt+1)-mp-1;build(1,len,1);
        for(int i=1;i<=tot;i++){
            int lala=lower_bound(mp+1,mp+len+1,G[i].x1)-mp;
            int lalala=lower_bound(mp+1,mp+len+1,G[i].x2)-mp;
            ans+=tree[1].res*(G[i].y-G[i-1].y),
            change(lala,lalala,G[i].v,1);
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

by >_< NeighThorn

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值