zoukankan      html  css  js  c++  java
  • 线段树+扫描线求矩形面积的交

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

    #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;
    }
    
  • 相关阅读:
    [转]jQuery 1.4的十五大新功能实例精讲
    数据库优化使用索引优化存储过程
    SQL语句练习实例之一——找出最近的两次晋升日期与工资额
    Sql Server中三种字符串合并方法的性能比较
    在IIS7下配置ASP.NET v1.1(Visual Studio .NET 2003)环境
    数据库优化方法 (一)
    WEB版一次选择多个文件进行批量上传(swfupload)的解决方案
    [转]根据性能监视器,分析性能瓶颈
    数据库优化方法(三)
    英文SilverLight 4 tools for vs 2010 安装于vs 2010中文版,无法拖拽数据源问题解决方法
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9489208.html
Copyright © 2011-2022 走看看