poj 1177 Picture 线段树加扫描线

求矩形周长的并
之前做过一个求矩形面积并的题目
用到了扫描线这种思想
这个题目可以照搬,作两次扫描线,一次x轴,一次y轴,同样标记入边,出边,当边是最外面的边时
周长就加上这条边的长度的两倍,入边标志为1,出边为-1,当加入边之后count==0,则表明了这条边是最外面的边。
看了解题报告,做法比较高效,一次扫描线就可以。下回再看。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define ls t<<1
#define rs t<<1|1
#define midt (tr[t].l+tr[t].r)>>1
using namespace std;
const int maxn=5011;
int x[maxn*2],y[maxn*2];
int ans;
struct no
{
    int y1,y2,x;
    int count;
    bool operator <(const no &xx) const
    {
        if(x==xx.x)
        return(count>xx.count);
        return(x<xx.x);
    }
}f[maxn*2];

struct node
{
    int x1,x2,y;
    int count;
    bool operator <(const node &xx) const
    {
        if(y==xx.y)
        return(count>xx.count);
        return(y<xx.y);
    }
}g[maxn*2];

struct
{
    int l,r;
    int low,high,count;
    int ture;
}tr[maxn*8];

int maketree(int t,int l,int r,int d[])
{
    tr[t].l=l;
    tr[t].r=r;
    tr[t].low=d[l];
    tr[t].high=d[r];
    tr[t].ture=1;
    tr[t].count=0;
    if(l+1==r)
    return(0);
    int mid=midt;
    maketree(ls,l,mid,d);
    maketree(rs,mid,r,d);
}

int pushdown(int t)
{
    tr[ls].count=tr[t].count;
    tr[ls].ture=1;
    tr[rs].count=tr[t].count;
    tr[rs].ture=1;
}

int modify(int t,int low,int high,int txt,int d[])
{
    if(tr[t].low==low&&tr[t].high==high&&tr[t].ture==1)
    {
        tr[t].count+=txt;
        if(tr[t].count==0)
        ans+=(tr[t].high-tr[t].low)*2;
        return(0);
    }
    if(tr[t].ture)
    pushdown(t);
    tr[t].ture=0;
    int mid=midt;
    if(high<=d[mid])
    modify(ls,low,high,txt,d);
    else if(d[mid]<=low)
    modify(rs,low,high,txt,d);
    else
    {
        modify(ls,low,d[mid],txt,d);
        modify(rs,d[mid],high,txt,d);
    }
}


int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            int x1,y1,x2,y2;
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            y[i]=y1;
            y[i+n]=y2;

            x[i]=x1;
            x[i+n]=x2;

            f[i].y1=y1;
            f[i].y2=y2;
            f[i].x=x1;
            f[i].count=1;

            f[i+n].y1=y1;
            f[i+n].y2=y2;
            f[i+n].x=x2;
            f[i+n].count=-1;

            g[i].x1=x1;
            g[i].x2=x2;
            g[i].y=y1;
            g[i].count=1;

            g[i+n].x1=x1;
            g[i+n].x2=x2;
            g[i+n].y=y2;
            g[i+n].count=-1;
        }

            sort(x+1,x+1+2*n);
            sort(y+1,y+1+2*n);
            sort(f+1,f+1+2*n);
            sort(g+1,g+1+2*n);

            ans=0;
            maketree(1,1,2*n,y);
            for(int i=1;i<=2*n;i++)
            {
                modify(1,f[i].y1,f[i].y2,f[i].count,y);
            }

            maketree(1,1,2*n,x);
            for(int i=1;i<=2*n;i++)
            {
                modify(1,g[i].x1,g[i].x2,g[i].count,x);
            }
            printf("%d\n",ans);

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值