hdu1828(矩形周长并)

Picture

题意:

  求n个矩形组成的图形的周长。

分析:

  用类似求矩形面积并的方法,但是需要注意的是当矩形相交时,位于别的矩形中的线是不需要加入周长中的,所以需要开数组记录是否出现相交,具体解释看代码。

  学习资料:大佬博客

代码:

#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;
#define ll long long
#define ull unsigned long long
#define cls(x) memset(x,0,sizeof(x))
#define clslow(x) memset(x,-1,sizeof(x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int maxn=1e5+100;
const int inf=0x3f3f3f3f;

int n,Case=1;

int cnt[maxn<<2];
//rt所代表的区间左边,右边是否有线段
bool lbd[maxn<<2],rbd[maxn<<2];
//segNum:rt所代表的区间有几条竖着的线段
//sum:rt所代表的区间有效线段的长度
int segNum[maxn<<2],sum[maxn<<2];

struct Seg {
    int l,r,h,s;
    Seg() {}
    Seg(int l,int r,int h,int s):l(l),r(r),h(h),s(s) {}
    bool operator < (const Seg& rhs) const {
        if(h==rhs.h)    return s>rhs.s;
        return h<rhs.h;
    }
};
Seg seg[maxn];

void PushUp(int rt,int l,int r)
{
    if(cnt[rt]){
        segNum[rt]=2;
        sum[rt]=r-l+1;
        lbd[rt]=rbd[rt]=1;
    }
    else if(l==r){
        sum[rt]=segNum[rt]=lbd[rt]=rbd[rt]=0;
    }
    else{
        lbd[rt]=lbd[rt<<1];
        rbd[rt]=rbd[rt<<1|1];
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        segNum[rt]=segNum[rt<<1]+segNum[rt<<1|1];
        //左右两个区间出现交集
        if(lbd[rt<<1|1]&&rbd[rt<<1])    segNum[rt]-=2;
    }
}

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

int main()
{
//    freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF&&n)
    {
        int m=0,l=inf,r=-inf;
        for(int i=1;i<=n;i++){
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            l=min(l,x1);r=max(r,x2);
            seg[m++]=Seg(x1,x2,y1,1);
            seg[m++]=Seg(x1,x2,y2,-1);
        }

        sort(seg,seg+m);
        int ans=0,last=0;
        for(int i=0;i<m;i++){
            if(seg[i].l<=seg[i].r)  update(seg[i].l,seg[i].r-1,seg[i].s,l,r-1,1);
            ans+=segNum[1]*(seg[i+1].h-seg[i].h);
            //需要减去重复覆盖的部分
            ans+=abs(sum[1]-last);
            last=sum[1];
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/shutdown113/p/9350267.html