HDU 1828 Picture

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828


题意:求重叠矩形的周长


思路:也是运用了扫描线,每一次更新后的tsum减去之前的tsum就是这次周长增长(上边处理理解有些不同,画了张图理解),由于周长要计算所有的边要到cnt(面积只要到cnt-1


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 20030
using namespace std;

struct Tree
{
    int l,r;
    int tsum,snum;
}tree[maxn*3];

int lazy[maxn*3],lseg[maxn*3],rseg[maxn*3],cnt,pos[maxn];

struct Node
{
    int l,r,h,date;
}s[maxn];

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

void getlen(int root)
{
    if(lazy[root])
    {
        tree[root].tsum=pos[tree[root].r+1]-pos[tree[root].l];
        lseg[root]=1;
        rseg[root]=1;
        tree[root].snum=2;
    }
    else if (tree[root].l==tree[root].r)
    {
        tree[root].tsum=0;
        lseg[root]=0;
        rseg[root]=0;
        tree[root].snum=0;
    }
    else
    {
        tree[root].tsum=tree[root<<1].tsum+tree[root<<1|1].tsum;
        tree[root].snum=tree[root<<1].snum+tree[root<<1|1].snum;
        lseg[root]=lseg[root<<1];
        rseg[root]=rseg[root<<1|1];
        if (rseg[root<<1] && lseg[root<<1|1]) tree[root].snum-=2;
    }
}

void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].tsum=tree[root].snum=0;
    if (l==r) return;
    int mid=(tree[root].l+tree[root].r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}

void update(int root,int l,int r,int val)
{
    if (tree[root].l>=l && tree[root].r<=r)
    {
        lazy[root]+=val;
        getlen(root);
        return;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if (l<=mid) update(root<<1,l,r,val);
    if (r>mid) update(root<<1|1,l,r,val);
    getlen(root);
}

void getline(int l,int r,int h,int val)
{
    s[cnt].l=l;
    s[cnt].r=r;
    s[cnt].h=h;
    s[cnt].date=val;
    cnt++;
}


int main()
{
    int n,num;
    while (scanf("%d",&n)!=EOF)
    {
        cnt=0;
        num=0;
        memset(lazy,0,sizeof(lazy));
        memset(lseg,0,sizeof(lseg));
        memset(rseg,0,sizeof(rseg));
        for (int i=0;i<n;i++)
        {
            int x1,x2,y1,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            getline(x1,x2,y1,1);
            getline(x1,x2,y2,-1);
            pos[num++]=x1;
            pos[num++]=x2;
        }
        sort(s,s+cnt,cmp);
        sort(pos,pos+num);

        int tem=1,last=0,res=0;
        for (int i=1;i<num;i++)
        {
            if (pos[i]!=pos[i-1])
             pos[tem++]=pos[i];
        }
        build(1,0,tem);
        s[cnt].h=s[cnt-1].h;
        for (int i=0;i<cnt;i++)
        {
            int l=lower_bound(pos,pos+tem,s[i].l)-pos;
            int r=lower_bound(pos,pos+tem,s[i].r)-pos-1;
            update(1,l,r,s[i].date);
            res+=abs(last-tree[1].tsum);
            res+=tree[1].snum*(s[i+1].h-s[i].h);
            last=tree[1].tsum;
        }
        printf("%d\n",res);
    }
}


),snum是来保存没有被覆盖的竖边,lseg和rseg是标记该区间是否被覆盖,如果左子树的rseg和右子树的lseg被覆盖就代表有2个矩形是重叠的因此snum数目需要-2



扫描线走到A的时候,将边1的区间标记,tsum加上边1的长度(初始为0),减去last的长度(初始为0)

扫描线走到B的时候,将边2的区间标记,tsum加上边2没有和边1重合的长度,减去last长度(上一步的tsum)

扫描线走到C的时候,和上2步类似

扫描线走到D的时候,由于边4是上边,边4的区间标记-1,但是由于其他边已经覆盖该区间,tsum没有影响

扫描线走到E的时候,边5的区间-1,tsum减去标记为0的区间,在和last的差值就是该位置增加的区间



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值