线段树扫描线

题目链接
注意这个题是以0结尾的坑了我半天
大佬的博客里面有详解

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e4+10;
double x[maxn];
struct zp
{
    double x1,x2,y,flag;
} arr[maxn*4];
bool cmp(zp a,zp b)
{
    return a.y<b.y;
}
struct tree
{
    int l,r;
    double num,lazy;//lazy不是0代表这段区间被覆盖,为0代表没有被覆盖
} node[maxn*4];
void pushup(int k)
{
    int l=node[k].l,r=node[k].r;          //这里加1
    if(node[k].lazy!=0) node[k].num=x[r+1]-x[l];//没有被覆盖则该段区间值为区间所离散化的长度
    else if(l==r) node[k].num=0;
    else node[k].num=node[k<<1].num+node[k<<1|1].num;//没有被覆盖则是他两个儿子节点的值之和
}
void build_tree(int l,int r,int k)//建树
{
    node[k].l=l,node[k].r=r,node[k].lazy=node[k].num=0;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build_tree(l,mid,k<<1);
    build_tree(mid+1,r,k<<1|1);
}
void update(int l,int r,int k,double num)
{
    if(node[k].l==l&&node[k].r==r)
    {
        node[k].lazy+=num;
        pushup(k);
        return ;
    }
    int mid=(node[k].l+node[k].r)>>1;
    if(r<=mid)
        update(l,r,k<<1,num);
    else if(l>mid)
        update(l,r,k<<1|1,num);
    else
        update(l,mid,k<<1,num),update(mid+1,r,k<<1|1,num);
    pushup(k);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(n==0)//神坑
            break;
        build_tree(1,4*n,1);
        for(int i=1; i<=n; i++)
        {
            double a,b,c,d;
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            arr[2*i-1].x1=arr[2*i].x1=a;
            arr[2*i-1].x2=arr[2*i].x2=c;
            arr[2*i-1].y=b,arr[2*i].y=d;
            arr[2*i-1].flag=1,arr[2*i].flag=-1;//1代表矩形的下线,-1代表上线,扫过之后就相当于不存在
            x[2*i-1]=a,x[2*i]=c;
        }
        n=2*n;
        sort(arr+1,arr+n+1,cmp);
        sort(x+1,x+n+1);//离散化坐标点
        double ans=0;
        for(int i=1;i<=n;i++)
        {
            int l=lower_bound(x+1,x+n+1,arr[i].x1)-x;
            int r=lower_bound(x+1,x+n+1,arr[i].x2)-x-1;//这里减一是为了好处理区间的和对应pushup里的+1
            if(l<=r) update(l,r,1,arr[i].flag);
            ans+=node[1].num*(arr[i+1].y-arr[i].y);
        }
        printf("%.2lf\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值