HDU 1828 Picture

29 篇文章 0 订阅
6 篇文章 0 订阅

HDU 1828 Picture

扫描线,矩形周长并

题意

求矩形周长并

思路

没有想象的难。根面积一样的离散化,线段树保存:

struct Stree
{
    int cov;//被完全覆盖的次数
    int len;//被覆盖的长度
    int num;//区间内线段的数量
    int lp, rp;//被覆盖的左端点和右端点
}stree[MAXN<<3];

保存区间内线段的数量,更新时通过左端点和右端点信息判断区间有几段线段。统计周长时:

int la=0, ans=0;
for(int i=1;i<=m;i++)
{
    int l=lower_bound(hax+1, hax+k+2, line[i].l)-hax;
    int r=lower_bound(hax+1, hax+k+2, line[i].r)-hax-1;
    update(l, r, line[i].fl, 1, k, 1);
    int tmp=abs(stree[1].len-la);
    la=stree[1].len;
    ans+=tmp;
    if(i!=m) ans+=stree[1].num*2*(line[i+1].h-line[i].h);
}

每次加的长度就是当前长度减上一次长度,同时加上区间内线段数量*2*高度差,就是竖着的那部分线段。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=5005;
struct Line
{
    int l, r;
    int h;
    int fl;
    Line() {}
    Line(int _l, int _r, int _h, int _fl) { l=_l, r=_r, h=_h, fl=_fl; }
    bool operator <(const Line &l)const
    {
        return h<l.h;
    }
}line[MAXN<<1];
int hax[MAXN<<1];

struct Stree
{
    int cov;//被完全覆盖的次数
    int len;//被覆盖的长度
    int num;//区间内线段的数量
    int lp, rp;//被覆盖的左端点和右端点
}stree[MAXN<<3];
void pushup(int l, int r, int rt)
{
    if(stree[rt].cov)
    {
        stree[rt].len=hax[r+1]-hax[l];
        stree[rt].num=1;
        stree[rt].lp=l, stree[rt].rp=r;
    }
    else if(l==r)
    {
        stree[rt].cov=stree[rt].len=0;
        stree[rt].num=0;
        stree[rt].lp=stree[rt].rp=0;
    }
    else
    {
        stree[rt].len=stree[rt<<1].len+stree[rt<<1|1].len;
        stree[rt].lp=stree[rt<<1].lp, stree[rt].rp=stree[rt<<1|1].rp;
        stree[rt].num=stree[rt<<1].num+stree[rt<<1|1].num;
        if(stree[rt<<1].rp+1==stree[rt<<1|1].lp)
            stree[rt].num--;
    }
}
void build(int l, int r, int rt)
{
    M(stree, 0);
}
void update(int L, int R, int c, int l, int r, int rt)
{
    if(L<=l&&r<=R)
    {
        stree[rt].cov+=c;
        pushup(l, r, rt);
        return;
    }
    int mid=(l+r)>>1;
    if(R<=mid) update(L, R, c, lson);
    else if(mid<L) update(L, R, c, rson);
    else
    {
        update(L, R, c, lson);
        update(L, R, c, rson);
    }
    pushup(l, r, rt);
}

int main()
{
    int n;
    while(scanf("%d", &n)==1)
    {
        int m=2*n;
        for(int i=1;i<=2*n;i+=2)
        {
            int a, b, c, d;scanf("%d%d%d%d", &a, &b, &c, &d);
            line[i]=Line(a, c, b, 1);
            line[i+1]=Line(a, c, d, -1);
            hax[i]=a, hax[i+1]=c;
        }
        sort(line+1, line+m+1);
        sort(hax+1, hax+m+1);
        int k=unique(hax+1, hax+m+1)-hax-2;
        build(1, k, 1);

        int la=0, ans=0;
        for(int i=1;i<=m;i++)
        {
            int l=lower_bound(hax+1, hax+k+2, line[i].l)-hax;
            int r=lower_bound(hax+1, hax+k+2, line[i].r)-hax-1;
            update(l, r, line[i].fl, 1, k, 1);
            int tmp=abs(stree[1].len-la);
            la=stree[1].len;
            ans+=tmp;
            if(i!=m) ans+=stree[1].num*2*(line[i+1].h-line[i].h);
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值