(使用線段樹實現的)掃描線算法

(使用線段樹實現的)掃描線算法

1、算法應用場景

  一個空間中存在若干矩形,且矩形的放置方向一致——(矩形的每條邊必然和X或者Y軸平行)c++

  求這些矩形覆蓋的總面積的大小。(存在若干個矩形相互重疊的問題)算法

 

2、解決思路

  考慮線段樹能夠logN的時間內作到區間覆蓋,區間設置特殊值。所以應當採用線段樹進行計算。this

  考慮使用線段樹維護當前X軸的長度,則面積應當爲:Σlength*hight。其中hight爲當前Y軸長度減去上一個Y軸長度。length爲當前維護的結果。spa

  考慮當將矩形切割成兩條形如,x1,x2,y,val的命令,其中x1,x2表明當前上線/下線的長度;y表明當前高度,val取1或-1分別帶至矩形的起始邊和結束邊。code

 

3、代碼實現

  對於當前應用場景,具備很明顯的特色,及,對於任意一個矩形,都必然將初始邊和結束邊加進線段樹中。則若某給定區間爲a,b時,不存在當a,b邊對應的結束邊還未被加進線段樹時就被清零或部分清零的可能性。blog

  所以,對於任意區間,都有顯而易見的兩種狀態:ci

    1,明確的知道該區間已經被填滿。——則區間長度爲區間所能表示的上下限之差。it

    2,不知道該區間是否被填滿。——則區間長度爲兩個子區間之差。io

  對於2狀況有一個子狀態:及當前區間僅僅包含一個元素:(a == b-1) ——我代碼中區間定義爲左閉右開。對於該區間,若無明確的增長指令,則應當認爲區間長度爲0。ast

#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\nTotal explored area: %.2f\n\n",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;
}
相關文章
相關標籤/搜索