• poj1511,线段树扫描线面积


    经典题,线段树扫描线其实类似区间更新,一般的做法是想象一根扫描线从上扫到下或者从左扫到右,本题的做法是从上扫到下

    只要扫到了一根水平线,就将其更新到线段树对应区间中,区间和它的子区间是独立更新的

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define maxn 2000
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    struct Seg{
        double l,r,h;
        int d;
        Seg(){}
        Seg(double a,double b,double c,int dd):l(a),r(b),h(c),d(dd){}
        bool operator<(const Seg & a)const{
            return h<a.h;
        }//从下往上扫描
    }segs[maxn];//横线段
    double data[maxn];
    int tot,m;//data统计高度
    int cnt[maxn<<2];//覆盖了这一整个区间的入边数 - 覆盖了这一整个区间的出边数 
    double sum[maxn<<2];//区间当前被覆盖的长度
    inline void pushup(int l,int r,int rt){
        //前两个if对应的是update中(L<=l && R>=r)的pushup,后一个if对应的是分开更新后的update
        if(cnt[rt])//如果这个区间都被覆盖了
            sum[rt]=data[r+1]-data[l];
        else if (l==r)//如果是单位段并且cnt[rt]==0,说明这一段就是没有被覆盖
            sum[rt]=0;
        else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    //更新函数update:如果整个区间被更新,分三种情况:1.这个区间被完全覆盖 2.这个区间是空白单位区间(没有子区间) 3.这个区间没有被完全覆盖 
    void update(int L,int R,int c,int l,int r,int rt){
        if(L<=l && R>=r){
            cnt[rt]+=c;
            pushup(l,r,rt);//为什么这里也会有pushup?因为pushup的功能不只是合并两个区间而已,它还能计算这个区间的覆盖长度 
            return; 
        }
        int m=l+r>>1;
        if(L<=m) update(L,R,c,lson);
        if(R>m) update(L,R,c,rson);
        pushup(l,r,rt);
    }
    void init(){
        tot=m=0;
        memset(cnt,0,sizeof cnt);
        memset(sum,0,sizeof sum);
    }
    int main(){
        int T=0,n;
        while(scanf("%d",&n) && n){
            init();
            
            for(int i=1;i<=n;i++){
                double x1,y1,x2,y2;
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                segs[tot]=Seg(x1,x2,y1,1);data[tot++]=x1;
                segs[tot]=Seg(x1,x2,y2,-1);data[tot++]=x2;
            }
            sort(segs,segs+tot);
            sort(data,data+tot);
            m=unique(data,data+tot)-data;
    
            double ret=0;
            for(int i=0;i<tot;i++){
                int posl=lower_bound(data,data+m,segs[i].l)-data;
                int posr=lower_bound(data,data+m,segs[i].r)-data-1;
                if(posl<=posr) 
                    update(posl,posr,segs[i].d,0,m,1);//把这条边更新到线段树中
                ret+=sum[1]*(segs[i+1].h-segs[i].h);
            }
            printf("Test case #%d
    Total explored area: %.2lf
    
    ",++T , ret);
        }
        return 0;
    }
  • 相关阅读:
    分布式文件系统技术选型
    .net core 与nginx笔记
    分布式场景
    c printf函数
    c 编程范式
    VS2019 卡顿,甚至卡死
    SQL Server 跨服务器查询
    递归 0到100求和
    moment js 制作倒计时 比较简单
    关于地狱回调的理解
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9941032.html
Copyright © 2020-2023  润新知