POJ 1177-Picture线段树+离散化+扫描线求矩形周长并

周长并和面积并的代码基本上差不多,只不过多了两个rb,lb判定端点是否被覆盖的判断,维护的过程也增加了一点难度,但是整体上是差不多的。

View Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include <algorithm>
#define N 5005
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node
{
    int l,r,num,len,cov;
    int lf,rf;
    bool rb,lb;
};
node tree[N<<2];
struct seg
{
    int x,y1,y2,flag;
};
seg line[N<<1];
int y[N<<1],cnt;
int cmp1(const void *a,const void *b)
{
    return *(int *)a-*(int *)b;;
}
int cmp2(const void *a,const void *b)
{
    seg *c=(seg *)a;
    seg *d=(seg *)b;
    return c->x-d->x;
}
void add(int x1,int x2,int y1,int y2)
{
    line[cnt].x=x1,line[cnt].y1=y1,line[cnt].y2=y2,line[cnt].flag=1;
    cnt++;
    line[cnt].x=x2,line[cnt].y1=y1,line[cnt].y2=y2,line[cnt].flag=-1;
    cnt++;
}
void build(int l,int r,int i)
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].num=tree[i].len=0;
    tree[i].rb=tree[i].lb=false;
    tree[i].cov=0;
    tree[i].lf=y[l];
    tree[i].rf=y[r];
    if(r==l+1)
    return;
    int mid=(l+r)>>1;
    build(l,mid,L(i));
    build(mid,r,R(i));
}
void length(int i)
{
    if(tree[i].cov>0)
    {
        tree[i].len=tree[i].rf-tree[i].lf;
        tree[i].num=1;
        tree[i].rb=tree[i].lb=true;
        return;
    }
    else if(tree[i].l==tree[i].r-1)
    tree[i].num=tree[i].lb=tree[i].rb=tree[i].len=0;
    else
    {
        tree[i].rb=tree[R(i)].rb;
        tree[i].lb=tree[L(i)].lb;
        tree[i].len=tree[L(i)].len+tree[R(i)].len;
        tree[i].num=tree[L(i)].num+tree[R(i)].num-tree[L(i)].rb*tree[R(i)].lb;
    }
}
void update(seg l,int i)
{
    if(tree[i].lf==l.y1&&tree[i].rf==l.y2)
    {
        tree[i].cov+=l.flag;
        length(i);
        return;
    }
    if(l.y2<=tree[L(i)].rf)
    update(l,L(i));
    else if(l.y1>=tree[R(i)].lf)
    update(l,R(i));
    else
    {
        seg temp;
        temp=l;
        temp.y2=tree[L(i)].rf;
        update(temp,L(i));
        temp=l;
        temp.y1=tree[R(i)].lf;
        update(temp,R(i));
    }
    length(i);
}
int main()
{
    int n,i,j,x1,x2,y1,y2,m;
    while(~scanf("%d",&n))
    {
        cnt=0;
        m=0;
        for(i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            y[m++]=y1;
            y[m++]=y2;
            add(x1,x2,y1,y2);
        }
        qsort(y,m,sizeof(int),cmp1);
        qsort(line,cnt,sizeof(seg),cmp2);
        int t=m;
        t=unique(y,y+m)-y;
        build(0,t-1,1);
        int lines,last,ans;
        lines=last=ans=0;
        line[cnt]=line[cnt-1];
        for(i=0;i<cnt;i++)
        {
            update(line[i],1);
            if(i)
            ans+=2*lines*(line[i].x-line[i-1].x);
            ans+=abs(tree[1].len-last);
            last=tree[1].len;
            lines=tree[1].num;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/caozhenhai/archive/2012/08/13/2636941.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值