• (使用线段树实现的)扫描线算法


    (使用线段树实现的)扫描线算法

    一、算法应用场景

      一个空间中存在若干矩形,且矩形的放置方向一致——(矩形的每条边必然和X或者Y轴平行)

      求这些矩形覆盖的总面积的大小。(存在若干个矩形相互重叠的问题)

    二、解决思路

      考虑线段树可以logN的时间内做到区间覆盖,区间设置特殊值。因此应当采用线段树进行计算。

      考虑使用线段树维护当前X轴的长度,则面积应当为:Σlength*hight。其中hight为当前Y轴长度减去上一个Y轴长度。length为当前维护的结果。

      考虑当将矩形切割成两条形如,x1,x2,y,val的命令,其中x1,x2代表当前上线/下线的长度;y代表当前高度,val取1或-1分别带至矩形的起始边和结束边。

     

    三、代码实现

      对于当前应用场景,具有很明显的特点,及,对于任意一个矩形,都必然将初始边和结束边加进线段树中。则若某给定区间为a,b时,不存在当a,b边对应的结束边还未被加进线段树时就被清零或部分清零的可能性。

      因此,对于任意区间,都有显而易见的两种状态:

        1,明确的知道该区间已经被填满。——则区间长度为区间所能表示的上下限之差。

        2,不知道该区间是否被填满。——则区间长度为两个子区间之差。

      对于2情况有一个子状态:及当前区间仅仅包含一个元素:(a == b-1) ——我代码中区间定义为左闭右开。对于该区间,若无明确的增加指令,则应当认为区间长度为0。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    const ll MAXN= 1<<19;
    const ll MAXM = 2333;
    int t,n,sizeOfMap =0;;
    class Node
    {
        public:
            int l,r,number;
            double sum;
            double lf,rf;
    };
    Node tree[MAXN];
    
    class Command
    {
        public:
            double x1,x2,y;
            int val;
            
            const bool operator < (Command const &c)
            {
                return this->y < c.y;
            }
            Command(){}
            Command(double x1,double x2,double y,int v)
            {
                this->x1 = x1;
                this->x2 = x2;
                this->y = y;
                this->val = v;
            }        
    };Command commands[MAXM];
    int command_number = 0;
    
    void tree_init(int a,int b,int now)
    {
        tree[now].l = a;
        tree[now].r = b;
        tree[now].number = 0;
        tree[now].sum = 0;
        if(a == b-1)return;
        int mid = (a+b)/2;
        tree_init(a,mid,now*2);
        tree_init(mid,b,now*2+1);
    }
    
    double arr[MAXM];
    
    int find_pos(double tar)
    {
        return lower_bound(arr,arr+sizeOfMap,tar)-arr;
    }
    
    void update(int a,int b,int now,int key)
    {
        int l = tree[now].l;
        int r = tree[now].r;
        int mid = (l+r)/2;
        int num = tree[now].number;
        int lc = now * 2;
        int rc = now * 2 + 1;
        
        if(l == a && r ==b)
        {
            tree[now].number += key;
            if(tree[now].number == 0)
            {
                if(l == r-1)tree[now].sum =0;
                else tree[now].sum = tree[lc].sum + tree[rc].sum;
            }else tree[now].sum = arr[r]-arr[l];
            return ;
        }
        if(a < mid)
        {
            update(a,min(b,mid),lc,key);
            if(b > mid)update(mid,b,rc,key);
        }else update(a,b,rc,key);
    
        if(tree[now].number == 0)
        {
            if(l == r-1)tree[now].sum =0;
            else tree[now].sum = tree[lc].sum + tree[rc].sum;
        }else tree[now].sum = arr[r]-arr[l];
        return ;
            
        
    }
    int cases = 1;
    
    void init()
    {
        sizeOfMap = 0;
        command_number = 0;
        // cin>>n;
        for(int i=0;i<n;++i)
        {
            // cin>>arr[i];
            double a,b,c,d;
            cin>>a>>b>>c>>d;
            arr[sizeOfMap++] = a;
            arr[sizeOfMap++] = b;
            arr[sizeOfMap++] = c;
            arr[sizeOfMap++] = d;
            commands[command_number++]=Command(a,c,b,1);
            commands[command_number++]=Command(a,c,d,-1);
        }
        sort(arr,arr+sizeOfMap);
        sort(commands,commands+command_number);
        tree_init(0,sizeOfMap+2,1);
        double last = 0.0;
        double ans = 0;
        for(int i=0;i<command_number;++i)
        {
            double line_now = commands[i].y;
            if(line_now != last)
            {
                double hight = line_now - last;
                
                ans += hight * tree[1].sum;
                
                // cout<<tree[1].sum<<ends<<hight<<"last: "<<last<<ends<<line_now<<endl;
                
                last = line_now;
            }
            double x1 = commands[i].x1;
            double x2 = commands[i].x2;
            int val = commands[i].val;
            update(find_pos(x1),find_pos(x2),1,val);
        }
        
        // cout<<ans<<endl;
        printf("Test case #%d
    Total explored area: %.2f
    
    ",cases++,ans);
        
    }
    
    int main()
    {
        
        // freopen("data_scanner.in","r",stdin);
        cin.sync_with_stdio(false);
        // cin>>t;
        // for(int i=0;i<t;++i)
        while(cin>>n&&n)
        {
            init();
            // cout<<tree[1].sum<<endl;
        }
        
        
        return 0;
    }
  • 相关阅读:
    原生ajax四部曲
    jquery ajax参数
    java String format占位符
    servlet是什么
    直接插入排序算法
    通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的--20135334赵阳林
    信息安全系统设计基础第一周学习总结
    信息安全系统设计基础实验五:通讯协议设计
    信息安全系统设计第二次&第四次实验
    信息安全系统设计基础第一次实验报告
  • 原文地址:https://www.cnblogs.com/rikka/p/9061485.html
Copyright © 2020-2023  润新知