atlantis解题报告

算法:线段树+离散化+扫描线

思想:把矩形的两条侧边存起来,然后排序,所有的y坐标存起来,也排序。映射到一个整数值。

每次遇到一个边先求面积,如果是左边的话插入其y方向的测度,如果是右侧边的话删除y方向的测度。不断的向右扫描。

线段树优化保存y方向的测度。使询问由o(n)变为o(logn)

#include <iostream>

#include <algorithm>

#include <cstdio>

#include <cstring>

using namespace std;

#define LEFT(i) (i * 2)

#define RIGHT(i) (i * 2 + 1)

const int SIZE_OF_ARR = 256;

 

struct Edge

{

    double x, y1, y2;

    bool flag;

 

    bool operator<(const Edge a) const

    {

        return x < a.x;

    }

} edge[SIZE_OF_ARR];

double arry[SIZE_OF_ARR];

 

class segment_tree

{

private:

    const static int SIZE = 1001 * 8;

    int left[SIZE], right[SIZE], cnt[SIZE];

    double m[SIZE];

    void build(int l, int r, int n);

public:

    void initialize(int n);

    void insert(int l, int r, int n);

    void del(int l, int r, int n);

    double queury();

    void update(int n);

};

 

void segment_tree::del(int l, int r, int n)

{

    int mid = (right[n] + left[n]) / 2;

    if (l == left[n] && r == right[n])

        cnt[n]--;

    else

    {

        if (mid <= l)

            del(l, r, RIGHT(n));

        else if (r <= mid)

            del(l, r, LEFT(n));

        else

        {

            del(l, mid, LEFT(n));

            del(mid, r, RIGHT(n));

        }

    }

    update(n);

}

 

void segment_tree::update(int n)

{

    if (cnt[n])

        m[n] = arry[right[n]] - arry[left[n]];

    else

    {

        if (right[n] - left[n] == 1)

            m[n] = 0;

        else

            m[n] = m[LEFT(n)] + m[RIGHT(n)];

    }

}

 

void segment_tree::insert(int l, int r, int n)

{

    int mid = (right[n] + left[n]) / 2;

    if (l == left[n] && r == right[n])

        cnt[n]++;

    else

    {

        if (mid <= l)

            insert(l, r, RIGHT(n));

        else if (r <= mid)

            insert(l, r, LEFT(n));

        else

        {

            insert(l, mid, LEFT(n));

            insert(mid, r, RIGHT(n));

        }

    }

    update(n);

}

 

double segment_tree::queury()

{

    return m[1];

}

 

void segment_tree::initialize(int n)

{

    memset(m, 0, sizeof (m));

    memset(cnt, 0, sizeof (cnt));

    memset(left, 0, sizeof (left));

    memset(right, 0, sizeof (right));

    build(0, n, 1);

}

 

void segment_tree::build(int l, int r, int n)

{

    left[n] = l;

    right[n] = r;

    m[n] = 0;

    int mid = (l + r) / 2;

    if (r - l <= 1)

        return;

    build(l, mid, LEFT(n));

    build(mid, r, RIGHT(n));

}

segment_tree tree;

 

int main()

{

    int n, cs = 1;

    while (scanf("%d", &n) == 1 && n)

    {

        double x1, x2, y1, y2;

        for (int i = 0; i < n; i++)

        {

            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);

            edge[i * 2].x = x1;

            edge[i * 2 + 1].y1 = edge[i * 2].y1 = min(y1, y2);

            edge[i * 2 + 1].x = x2;

            edge[i * 2 + 1].y2 = edge[i * 2].y2 = max(y1,y2);

            arry[i * 2] = y1;

            arry[i * 2 + 1] = y2;

            if (x1 > x2)

            {

                edge[i * 2].flag = true;

                edge[i * 2 + 1].flag = false;

            }

            else

            {

                edge[i * 2].flag = false;

                edge[i * 2 + 1].flag = true;

            }

        }

        sort(edge, edge + n * 2);

        sort(arry, arry + n * 2);

        tree.initialize(n * 2);

        double area = 0;

        for (int i = 0; i < 2 * n; i++)

        {

            int a = lower_bound(arry, arry + 2 * n, edge[i].y1) - arry;

            int b = lower_bound(arry, arry + 2 * n, edge[i].y2) - arry;

            if (a == b)

                continue;

            if (i == 0)

            {

                tree.insert(a, b, 1);

                continue;

            }

            area += (edge[i].x - edge[i - 1].x) * tree.queury();

            if (edge[i].flag)

                tree.del(a, b, 1);

            else

                tree.insert(a, b, 1);

        }

        printf("Test case #%d\nTotal explored area: %0.2lf\n\n", cs++, area);

    }

    return 0;

}

你可能感兴趣的:(ant)