• 线段树+扫描线求矩形面积的交


    关于扫描线的存储,离散化就不多说了

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <string.h>
    #define lson rt<<1,left,mid
    #define rson rt<<1|1,mid,right
    #define eps 1e-8
    using namespace std;
    const int N = 2e3 + 10;
    const int inf = 0x3f3f3f3f;
    int n;
    struct Seg{
        double l,r,h;
        int d;
        Seg(){}
        Seg(double l,double r,double h,int d):l(l),r(r),h(h),d(d){}
        bool operator < (const Seg& rhs) const{
            if(h == rhs.h)return d > rhs.d;
            return h < rhs.h;
        }
    }a[N];
    int cnt[N << 2];//树的覆盖次数
    double all[N<<2];//x轴的离散化
    

     我们要更新维护的是覆盖一次的长度和覆盖两次以上的长度还有覆盖次数cnt

    double one[N << 2],two[N << 2];
    

     关键就是pup————更新操作

    先来分析,如果这个定点覆盖大于等于两次——》那么one数组和two数组可以直接利用边界更新

    如果覆盖一次one数组直接更新,如果是叶子节点two数组清零,非叶子节点two数组为其两个叶子节点的one数组之和————》这里我曾经产生了疑问——》

    其实也很好理解——》当前节点被覆盖了一次,覆盖标记我们是没有传递的,所以如果节点的one节点被覆盖(值非零)那么一合计他的值就可以上升为覆盖两次的值了

    如果一次都没有覆盖——》叶子结点——》one two清零——》非叶子节点——》向下寻找子节点更新

    void pup(int rt,int left,int right)
    {
        if(cnt[rt] >= 2)//覆盖超过了两次包括两次直接计算长度
        {
            two[rt] = all[right] - all[left];
            one[rt] = two[rt];
        }
        else if(cnt[rt] == 1)//仅仅才覆盖一次
        {
            one[rt] = all[right] - all[left];//计算覆盖一次的长度
            if(left + 1 == right)
            {
                two[rt] = 0.0;}//如果是叶子节点不必计算两次的长度
            else
            {
                two[rt] = one[rt<<1] + one[rt<<1|1];
            }//向上更新覆盖两次的长度(注意是包含的关系)
        }
        else//一次都没有完全覆盖的区间//仅仅考虑从下面向上传递的区间长度
        {
            if(left + 1 == right)
            {
                one[rt] = two[rt] = 0.0;
            }
            else
            {
                one[rt] = one[rt << 1] + one[rt << 1|1];
                two[rt] = two[rt<<1] + two[rt<<1|1];
            }
        }
    }
    

     剩下的代码我就觉得很中规中矩了……

    bool Equal(double x,double y)
    {
        return abs(x - y) < eps;
    }
    void update(double L,double R,int v,int rt,int left,int right)
    {
        if(Equal(L,all[left]) && Equal(R,all[right]))
        {
            cnt[rt] += v;
            pup(rt,left,right);
            //cout<<"    "<<L<<" "<<R<<" "<<cnt[rt]<<endl;
            return;
        }
    
        int mid = (left + right) >> 1;
    
        if(left + 1 < right)
        {
            if(R <= all[mid] + eps)update(L,R,v,lson);
            else if(L >= all[mid] - eps)update(L,R,v,rson);
            else
            {
                update(L,all[mid],v,lson);
                update(all[mid],R,v,rson);
            }
        }
    
        pup(rt,left,right);
    }
    void build(int rt,int left,int right)
    {
        one[rt] = 0.0;
        two[rt] = 0.0;
        cnt[rt] = 0.0;
        if(left + 1 == right)return;
        int mid = (left + right) >> 1;
        build(lson);
        build(rson);
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(int i = 0;i < n;i++)
            {
                double x1,y1,x2,y2;
                scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
                a[i] = Seg(x1,x2,y1,1);
                a[i+n] = Seg(x1,x2,y2,-1);
                all[i] = x1;
                all[i+n] = x2;
            }
            n <<= 1;
            sort(a,a+n);
            sort(all,all+n);
            int m = unique(all,all+n) - all;
    //        build(1,0,m-1);
            memset(cnt,0,sizeof(cnt));
            memset(one,0.0,sizeof(one));
            memset(two,0.0,sizeof(two))
            double ans = 0.0;
            for(int i = 0;i < n-1;++i){
                    //找到这条线段的区间范围进行更新
                //cout<<"now line    "<<a[i].l<<"    "<<a[i].r<<"   "<<a[i].h<<endl;
                //cout<<"next line   "<<a[i+1].l<<"    "<<a[i+1].r<<"   "<<a[i+1].h<<endl;
                update(a[i].l,a[i].r,a[i].d,1,0,m-1);
                //printf("%.2f   %.2f",one[1],two[1]);
                ans += two[1] * (a[i+1].h - a[i].h);
            }
            printf("%.2f
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Git配置文件
    Python操作Excel表格概括
    字符串时间转换为格式化时间
    windows 安装pip 及更换pip国内源
    JS数组遍历的方法汇总
    python文件读写操作(r/r+/rb/w/w+/wb/a/a+/ab)
    【Offer】Kafka面试题总结
    netdata开源Linux系统监控系统安装:配置项详解
    netdata开源Linux系统监控系统安装:一句话满足你的要求
    nginx配置禁特定路径下的反向代理
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9489208.html
Copyright © 2020-2023  润新知