CodeForces-610D 扫描线求面积并

CodeForces-610D

题意

给定一些平行于坐标轴的线段,线段的宽度为1,单位线段的面积为 1 .求所有线段的面积(并)的和

思路

只要找出右上角端点,横纵坐标都加 1 存储就行

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ls rt<<1
#define rs rt<<1|1
#define mid(rt) (p[rt].l+p[rt].r)>>1
using namespace std;
typedef long long ll;
const int maxn=1000010;
int tot;
struct edge
{
    ll l,r;
    ll h;
    int v;
}e[maxn<<2];
bool cmp(edge a,edge b)
{
    return a.h<b.h;
}
ll x[maxn<<2];
struct node
{
    int l,r;
    int cnt;
    ll len;
}p[maxn<<2];
void build(int l,int r,int rt)
{
    p[rt].l = l , p[rt].r = r;
    p[rt].cnt = p[rt].len = 0;
    if(l==r)
        return ;
    int m = mid(rt);
    build(l,m,ls);
    build(m+1,r,rs);
}
void pushup(int rt)
{
    if(p[rt].cnt)
        p[rt].len = x[p[rt].r+1] - x[p[rt].l];
    else if(p[rt].l==p[rt].r)
        p[rt].len = 0;
    else
        p[rt].len = p[ls].len + p[rs].len;
}
void update(int l,int r,int rt,int v)
{
    if(p[rt].l==l && p[rt].r==r)
    {
        p[rt].cnt += v;
        pushup(rt);
        return ;
    }
    int m = mid(rt);
    if(r<=m)
        update(l,r,ls,v);
    else if(l>m)
        update(l,r,rs,v);
    else
    {
        update(l,m,ls,v);
        update(m+1,r,rs,v);
    }
    pushup(rt);
}
void pre(ll x1,ll y1,ll x2,ll y2)
{
    if(x1>x2)
        swap(x1,x2);
    if(y1>y2)
        swap(y1,y2);
    x2 += 1 , y2 += 1;
    e[tot].l = e[tot+1].l = x[tot] = x1;
    e[tot].r = e[tot+1].r = x[tot+1] = x2;
    e[tot].h = y1;
    e[tot+1].h = y2;
    e[tot].v = 1;
    e[tot+1].v = -1;
    tot += 2;
}
int main()
{
    int n;
    tot=0;
    ll x1,x2,y1,y2;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        pre(x1,y1,x2,y2);
    }
    sort(e,e+tot,cmp);
    sort(x,x+tot);
    int k = unique(x,x+tot)-x;
    build(0,k-1,1);
    ll ans=0;
    for(int i=0;i<tot;i++)
    {
        int l=lower_bound(x,x+k,e[i].l)-x;
        int r=lower_bound(x,x+k,e[i].r)-x-1;
        update(l,r,1,e[i].v);
        ans += (e[i+1].h-e[i].h)*p[1].len;
    }
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值