hdu1828 扫描线计算周长

和扫描线计算面积差不多,新加了lbd,rbd线段树来标记区间的左右两侧是否被填充(左右边界是否存在),numbd线段树统计区间有多少边

/*数据弱不用离散化,但是要处理一下坐标*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 20005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct Seg{
    int l,r,h,s;
    Seg(){}
    Seg(int a,int b,int c,int d):l(a),r(b),h(c),s(d){}
    bool operator<(const Seg& a)const{
        if(h==a.h) return s>a.s;
        return h<a.h;
    }
}ss[maxn];
bool lbd[maxn<<2],rbd[maxn<<2];//该区间是否存在左边界,右边界,仅仅是用来判断
int numseg[maxn<<2];//该区间竖边的数量(0,2)
int cnt[maxn<<2];//覆盖了这一整个区间的入边-出边
int len[maxn<<2];//这个区间被覆盖的长度
void pushup(int rt,int l,int r){
    if(cnt[rt]){
        lbd[rt]=rbd[rt]=1;
        len[rt]=r-l+1;
        numseg[rt]=2;
    }
    else if(l==r)
        len[rt]=numseg[rt]=rbd[rt]=lbd[rt]=0;
    else {
        lbd[rt]=lbd[rt<<1];
        rbd[rt]=rbd[rt<<1|1];
        len[rt]=len[rt<<1]+len[rt<<1|1];
        numseg[rt]=numseg[rt<<1]+numseg[rt<<1|1];
        if(lbd[rt<<1|1] && rbd[rt<<1]) numseg[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(){
    int n;
    while(scanf("%d",&n)==1){
        int m=0;
        int lbd=10000,rbd=-10000;
        for(int i=0;i<n;i++){
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            lbd=min(lbd,a);
            rbd=max(rbd,c);
            ss[m++]=Seg(a,c,b,1);
            ss[m++]=Seg(a,c,d,-1);
        }
        sort(ss,ss+m);
        int ret=0,last=0;
        for(int i=0;i<m;i++){
            if(ss[i].l<ss[i].r) 
                update(ss[i].l,ss[i].r-1,ss[i].s,lbd,rbd,1);
            ret+=numseg[1]*(ss[i+1].h-ss[i].h);//竖边数量*区间高度
            ret+=abs(len[1]-last);
            last=len[1];
        }
        printf("%d
",ret);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zsben991126/p/9943650.html