线段树扫描线

线段树扫描线,矩形面积并,面积的求法模拟扫描线从下向上扫过图形,并快速计算当前扫描线被截得的长度。将横边赋上不同的权值,下边为1,上边为-1。所有横边按照y坐标生序排序,每次先碰到下边,再碰到上边。

矩形周长并,纵边总长度=sum(2被截的线段条数扫过的高度),横边总长度=sum(|上次截得的总长-现在截得的总长|)。

struct SegmentTreeScanLine{
    struct tree{
        int l,r,cnt/*被完全覆盖的次数*/,len/*区间内被截的长度*/,v/*区间内的线段条数*/;
        bool ls,rs;/*表示左右端点是否被覆盖*/
    }t[N<<2];
    struct scanline{
        int l,r,h,f;
        inline bool friend operator<(const scanline&a,const scanline&b){
            return a.h==b.h?a.f>b.f:a.h<b.h;
        }
    }line[N<<1];
    int val[N<<1];/*对横坐标离散化*/
    #define lc (p<<1)
    #define rc (p<<1|1)
    #define l(p) (t[p].l)
    #define r(p) (t[p].r)
    #define c(p) (t[p].cnt)
    #define le(p) (t[p].len)
    #define v(p) (t[p].v)
    #define ls(p) (t[p].ls)
    #define rs(p) (t[p].rs)
    void build(int p,int l,int r){
        t[p]={l,r};
        if(l==r)return;
        int mid=l+r>>1;
        build(lc,l,mid);
        build(rc,mid+1,r);
    }
    inline void pushup(int p){
        if(c(p)){/*被覆盖过*/
            le(p)=val[r(p)+1]-val[l(p)];/*上界-下界*/
            ls(p)=rs(p)=1;/*完全覆盖标记*/
            v(p)=1;
        }
        else{
            le(p)=le(lc)+le(rc);/*合并长度*/
            ls(p)=ls(lc);/*左儿子左端点被覆盖,则自己左端点一定被覆盖*/
            rs(p)=rs(rc);/*右儿子右端点被覆盖,则自己右端点一定被覆盖*/
            v(p)=v(lc)+v(rc);/*合并条数*/
            if(rs(lc)&&ls(rc))v(p)--;/*中间是连续的一段,条数-1*/
        }
    }
    void update(int p,int l,int r,int v){
        int x=l(p),y=r(p);/*l代表左区间l,值为val[l],r代表右区间r+1,值为val[r+1]*/
        if(val[y+1]<=l||r<=val[x])return;
        if(l<=val[x]&&val[y+1]<=r)return c(p)+=v,pushup(p),void();/*这里也需要pushup*/
        update(lc,l,r,v);
        update(rc,l,r,v);
        pushup(p);
    }
    inline void addline(int p,int x,int y,int a,int b){
        val[lc-1]=x;
        val[lc]=a;
        line[lc-1]={x,a,y,1};
        line[lc]={x,a,b,-1};
    }
    inline int area(int n){
        n<<=1;
        sort(line+1,line+1+n);
        sort(val+1,val+1+n);
        int m=unique(val+1,val+1+n)-val-1,re=0;
        build(1,1,m-1);/*注意是到m-1,[1,m-1]即[val[1],val[m]]*/
        for(int i=1;i<n;i++){/*最后一条边无需统计*/
            update(1,line[i].l,line[i].r,line[i].f);
            re+=t[1].len*(line[i+1].h-line[i].h);/*统计面积,根节点的长度乘上与下一条线的距离就是这一块内的矩形面积*/
        }
        return re;
    }
    inline int girth(int n){
        n<<=1;
        sort(line+1,line+1+n);
        sort(val+1,val+1+n);
        int m=unique(val+1,val+1+n)-val-1;
        build(1,1,m-1);
        int re=0,pre=0;
        for(int i=1;i<n;i++){
            update(1,line[i].l,line[i].r,line[i].f);
            re+=abs(pre-le(1));/*统计横边*/
            pre=le(1);
            re+=2*v(1)*(line[i+1].h-line[i].h);/*统计纵边*/
        }
        re+=line[n].r-line[n].l;/*累加最后一条线的长度*/
        return re;
    }
};
posted @ 2022-11-14 17:41  半步蒟蒻  阅读(46)  评论(0)    收藏  举报