【POJ1177】【HDU1828】【codevs2149】矩形面积周长并

传送门1
传送门2
传送门3
思路:
有点纸张的做法
不会记录竖向边的个数
于是横着做一遍扫描线,竖着做一遍扫描线
好像还挺正确的……
但实际上可以通过当前扫到的横向边的类型来记录竖向边的个数
唉:-(……
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define M 5005
using namespace std;
int n;
int b[M<<1],cover[M<<3],lazy[M<<3];
struct node{
    int up,down,data,tp;
}a[M<<1],c[M<<1];
bool cmp(node a,node b)
{
    if (a.data==b.data) return a.tp>b.tp;
    return a.data<b.data;
}
void update(int rt,int begin,int end,node x)
{
    if (x.up<=begin&&end<=x.down)
    {
        lazy[rt]+=x.tp;
        if (lazy[rt]) cover[rt]=b[end+1]-b[begin];
        else if (begin==end) cover[rt]=0;
        else cover[rt]=cover[rt<<1]+cover[rt<<1|1];
        return;
    }
    int mid=begin+end>>1;
    if (mid>=x.up) update(rt<<1,begin,mid,x);
    if (mid<x.down) update(rt<<1|1,mid+1,end,x);
    if (lazy[rt]) cover[rt]=b[end+1]-b[begin];
    else cover[rt]=cover[rt<<1]+cover[rt<<1|1];
}
int get(int rt,int begin,int end,node x)
{
    if (x.up<=begin&&end<=x.down) return cover[rt];
    if (cover[rt]==b[end+1]-b[begin]) return b[min(end,x.down)+1]-b[max(begin,x.up)]; 
    int mid=begin+end>>1,ans=0;
    if (mid>=x.up) ans+=get(rt<<1,begin,mid,x);
    if (mid<x.down) ans+=get(rt<<1|1,mid+1,end,x);
    return ans; 
}
main()
{
    scanf("%d",&n);
    int x,y,xx,yy;
    for (int i=1;i<=n;++i)
        scanf("%d%d%d%d",&x,&y,&xx,&yy),
        b[i*2-1]=y,b[i*2]=yy,
        a[i*2-1]=(node){y,yy,x,1},
        a[i*2]=(node){y,yy,xx,-1},
        c[i*2-1]=(node){x,xx,y,1},
        c[i*2]=(node){x,xx,yy,-1};
    sort(b+1,b+n*2+1);
    b[0]=unique(b+1,b+n*2+1)-b-1;
    for (int i=1;i<=n;++i)
        a[i*2-1].up=a[i*2].up=lower_bound(b+1,b+b[0]+1,a[i*2-1].up)-b,
        a[i*2-1].down=a[i*2].down=lower_bound(b+1,b+b[0]+1,a[i*2-1].down)-b-1;
    sort(a+1,a+n*2+1,cmp);
    int t=a[1].data,ans=0;
    for (int i=1;i<=n<<1;++i)
    {
            if (a[i].tp==1)
                ans+=b[a[i].down+1]-b[a[i].up]-get(1,1,b[0]-1,a[i]),
                update(1,1,b[0]-1,a[i]);
            else
                update(1,1,b[0]-1,a[i]),
                ans+=b[a[i].down+1]-b[a[i].up]-get(1,1,b[0]-1,a[i]);
        t=a[i].data;
    }
    for (int i=1;i<=n;++i)
        a[i*2-1]=c[i*2-1],
        a[i*2]=c[i*2],
        b[i*2-1]=a[i*2-1].up,
        b[i*2]=a[i*2].down;
    sort(b+1,b+n*2+1);
    b[0]=unique(b+1,b+n*2+1)-b-1;
    for (int i=1;i<=n;++i)
        a[i*2-1].up=a[i*2].up=lower_bound(b+1,b+b[0]+1,a[i*2-1].up)-b,
        a[i*2-1].down=a[i*2].down=lower_bound(b+1,b+b[0]+1,a[i*2-1].down)-b-1;
    sort(a+1,a+n*2+1,cmp);
    t=a[1].data;
    for (int i=1;i<=n<<1;++i)
    {
            if (a[i].tp==1)
                ans+=b[a[i].down+1]-b[a[i].up]-get(1,1,b[0]-1,a[i]),
                update(1,1,b[0]-1,a[i]);
            else
                update(1,1,b[0]-1,a[i]),
                ans+=b[a[i].down+1]-b[a[i].up]-get(1,1,b[0]-1,a[i]);
        t=a[i].data;
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值