Codeforces Gym 101505D Orchard Division(离散化+树状数组+扫描线+二分)

Orchard Division

orchard.c, orchard.cpp, orchard.c11, Orchard.java, orchard.py

Uncle Oliver isgoing to sell a significant part of his famous dwarf plum tree orchard. He isgoing to divide the orchard into two parts, sell the first one and keep theother one.

The trees wereoriginally planted in regular rows and columns forming a rectangular grid withthe same number of rows and columns. As years went by, Oliver removed manytrees which were weak or plagued by bugs so nowadays there is also a lot offree squares unoccupied by any tree.

Oliver hasdecided that he will keep exactly half of all the trees in the orchard.Moreover, he has few additional demands which, in his opinion, will ensure easymaintenance of his part in the future.

•    The part Oliver is going to keep should be in theshape of a rectangle.

•    A least one corner of the rectangle shouldcoincide with a corner of the orchard.

•    The rectangle area should be as small aspossible.

Originally, eachtree was planted in the center of an imaginary square whose area was exactlyone square meter. Thus, the position of each tree can be described by thecoordinates of the square on which it is standing. The dividing fence betweenthe two parts of the orchard will run along the borders of the squares.

Input Specification

There are moretest cases. Each case starts with a line containing two integersM (1 ≤ M ≤ 109) and N (1≤ N ≤ 106) separated byspace. The orchard side length in meters is expressed byM and the number of trees in the orchard is expressed by N. Next, there areN lines, each line specifies xand y coordinates of one tree inthe orchard. The coordinates are separated by space. For simplicity reasons, weassume that the coordinates are zero based, so the coordinates of the squaresin the corners of the orchard are (0,0),(0,M−1),(M −1,M −1),(M−1,0). All coordinate pairs (x,y) in one test case are unique.

Output Specification

For each testcase, print a single line with one whole number A denoting the minimum possible area in square meters of uncleOliver’s part of the orchard. If it is not possible to divide the orchardaccording to Oliver’s demands print “-1”. Note that the output value might not fit into 32-bit integer type.

Sample Input

6 8

4 5

1 4

0 3

5 3

1 2

3 2

3 1

2  0

3  3

2 0

1 1

0 2

2 2

0  0

1  1

Output for Sample Input

12

-1

1



【思路】

首先数据范围很大,点数却没那么大,也就需要先对坐标进行离散化。然后对所有的点进行双关键字排序,接下来进行扫描线操作。第一遍扫描线从高到低扫,维护横坐标出现的的次数,并查询前缀和为总点数一半的那个点的位置,以及后缀和为总点数一半的那个点的位置,可以据此算出面积;第二遍从低到高扫,也是一样分前缀和后缀来算。面积最小的那个正是答案。维护和查询横坐标出现次数用树状数组,由于sum函数具有递增性,查找某个点的位置时可以二分查找。这里两个优化中的一个不做都会TLE,另外二分时应该注意,找前缀的那次要尽可能找左边的点,找后缀的那次要尽可能找右边的点。


【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

const int MAXN = 1e6 + 5;
const long long INF = 0x3f3f3f3f3f3f3f3f;

struct point {
    long long x, y;

    bool operator<(const point &another) const
    {
        if (y == another.y)
            return x < another.x;
        return y < another.y;
    }
};

int n, ord;
long long m;
int a[MAXN];
long long num[MAXN];
point p[MAXN];
map<long long, int> id;

int lowbit(int x)
{
    return (x & -x);
}

void modify(int x, int num)
{
    while (x <= ord) {
        a[x] += num;
        x += lowbit(x);
    }
}

int sum(int x)
{
    int ans = 0;
    while (x > 0) {
        ans += a[x];
        x -= lowbit(x);
    }
    return ans;
}

bool cmp(const point &a, const point &b)
{
    return a.x < b.x;
}

int binsearch_l(int num)
{
    int l = 1, r = ord, ans;
    while (l + 1 < r) {
        int mid = (l + r) >> 1;
        if (sum(mid) < num)
            l = mid + 1;
        else
            r = mid;
    }
    if (sum(l) == num)
        ans = l;
    else
    if (sum(r) == num)
        ans = r;
    else
        ans = 0;
    return ans;
}

int binsearch_r(int num)
{
    int l = 1, r = ord, ans;
    while (l + 1 < r) {
        int mid = (l + r) >> 1;
        if (sum(ord) - sum(mid - 1) > n / 2)
            l = mid + 1;
        else
            r = mid;
    }
    if (sum(ord) - sum(r - 1) == n / 2)
        ans = r;
    else
    if (sum(ord) - sum(l - 1) == n / 2)
        ans = l;
    else
        ans = 0;
    return ans;
}

int main()
{
    while (scanf("%lld %d", &m, &n) == 2) {
        for (int i = 1; i <= n; i++) {
            scanf("%lld %lld", &p[i].x, &p[i].y);
            p[i].x++; p[i].y++;
        }
        if (n % 2 == 0) {
            sort(p + 1, p + 1 + n, cmp);
            ord = 0; id.clear();
            for (int i = 1; i <= n; i++)
                if (!id.count(p[i].x)) {
                    id[p[i].x] = ++ord;
                    num[ord] = p[i].x;
                }
            sort(p + 1, p + 1 + n);
            int index;
            long long ans = INF;
            memset(a, 0, sizeof(a));
            index = 1;
            while (index <= n) {
                while (index + 1 <= n && p[index].y == p[index + 1].y) {
                    modify(id[p[index].x], 1);
                    index++;
                }
                modify(id[p[index].x], 1);
                if (index < n / 2) {index++; continue;}
                int pos;
                pos = binsearch_l(n / 2);
                if (pos != 0) ans = min(ans, num[pos] * p[index].y);
                pos = binsearch_r(n / 2);
                if (pos != 0) ans = min(ans, (m - num[pos] + 1) * p[index].y);
                index++;
            }
            memset(a, 0, sizeof(a));
            index = n;
            while (index >= 1) {
                while (index - 1 >= 1 && p[index].y == p[index - 1].y) {
                    modify(id[p[index].x], 1);
                    index--;
                }
                modify(id[p[index].x], 1);
                if (n - index + 1 < n / 2) {index--; continue;}
                int pos;
                pos = binsearch_l(n / 2);
                if (pos != 0) ans = min(ans, num[pos] * (m - p[index].y + 1));
                pos = binsearch_r(n / 2);
                if (pos != 0) ans = min(ans, (m - num[pos] + 1) * (m - p[index].y + 1));
                index--;
            }
            if (ans == INF)
                printf("-1\n");
            else
                printf("%lld\n", ans);
        }
        else
            printf("-1\n");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值