hdu 1828 求矩形并的周长

昨天学完了矩形的并求面积,是看看小HH的博客做的。。大概对扫描线有一个初步的了解,今天果断学习求矩形的并的周长,哎,明显费劲很多,但本菜坚决没有看大牛的代码,果断自己独立完成,而且1A。。。。

预处理不说了,和求矩形并的面积是一样的,只不过要把左右边也要存储在一个数组中,然后排序离散化。。略。重点说以下线段树部分,先说处理横向线段。对每一条线段做查询和更新操作,查询就是求新线段中未覆盖部分,更新则改变该条线段的状态。。。若是底边,先查询,后更新。若是上边,则顺序相反。处理左右边与上下边是一样的,附代码:

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define cl(a) memset(a,0,sizeof(a))
#define N 10010
#define ss(a) scanf("%d",&a)
#define read(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)

using namespace std;

struct seg
{
    int l;
    int r;
    int h;
    int t;
    seg(){}
    seg(int a,int b,int c,int d):l(a),r(b),h(c),t(d)
    {
    }
}line[N],vert[N];

int sum[N<<3],col[N<<3],x[N],res,y[N];

bool cmp(seg p,seg q)
{
    return p.h<q.h;
}

int bin(int key,int l,int r)
{
    if (r-l<=1)
    {
        if (key==x[l]) return l;
        else return r;
    }
    int m=(l+r)/2;
    if (key==x[m]) return m;
    else if (key<x[m]) return bin(key,l,m-1);
    else return bin(key,m+1,r);
}

void pushup(int l,int r,int rt)
{
    if (col[rt]) sum[rt]=0;
    else if (l==r) sum[rt]=x[r+1]-x[l];
    else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void build(int l,int r,int rt)
{
    if (l==r) 
    {
        sum[rt]=x[r+1]-x[l];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(l,r,rt);
}

void update(int L,int R,int c,int l,int r,int rt)
{
    if (L<=l&&r<=R)
    {
        col[rt]+=c;
        pushup(l,r,rt);
        return;
    }
    int m=(l+r)>>1;
    if (L<=m) update(L,R,c,lson);
    if (R>m) update(L,R,c,rson);
    pushup(l,r,rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if (col[rt]) return 0;
    if (L<=l&&r<=R) return sum[rt]; 
    int m=(l+r)>>1,res=0;
    if (L<=m) res+=query(L,R,lson);
    if (R>m) res+=query(L,R,rson);
    return res;
}                       

void deal(int m,int k)
{
    cl(sum);cl(col);
    build(1,k,1);
    int i,l,r,t0;
    for (i=1;i<=m;i++)
    {
        l=bin(line[i].l,1,k);
        r=bin(line[i].r,1,k)-1;
        t0=line[i].t;
        if (l>r) continue;
        if (t0==1) 
        {
            res+=query(l,r,1,k,1);
            update(l,r,1,1,k,1);
        }
        else
        {
            update(l,r,-1,1,k,1);
            res+=query(l,r,1,k,1);
        }
    }  
}

int main()
{
    int n,i;
    while (ss(n)!=EOF)
    {
        int a,b,c,d;
        int m=0,k=1;
        for (i=1;i<=n;i++)
        {
            read(a,b,c,d);
            line[++m]=seg(a,c,b,1);
            vert[m]=seg(b,d,a,1);
            x[m]=a;
            y[m]=b;
            line[++m]=seg(a,c,d,-1);
            vert[m]=seg(b,d,c,-1);
            x[m]=c;
            y[m]=d;
        }
        sort(x+1,x+m+1);
        sort(line+1,line+m+1,cmp);
        for (i=2;i<=m;i++)
            if (x[i]!=x[i-1]) x[++k]=x[i];
        res=0;
        deal(m,k);
        sort(y+1,y+m+1);
        sort(vert+1,vert+m+1,cmp);
        k=1;
        x[1]=y[1];
        line[1]=vert[1];
        for (i=2;i<=m;i++)
        {
            if (y[i]!=y[i-1]) x[++k]=y[i];
            line[i]=vert[i];
        }
        deal(m,k);      
        printf("%d\n",res);
    }
    return 0;
}           


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值