ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 P2163 SHOI2007 园丁的烦恼

2019-08-10 14:01:54  阅读:231  来源: 互联网

标签:int 题解 id P2163 MAXN another SHOI2007 矩形 我们


转载自:https://lornd.top/index.php/archives/25/

二维数点(树状数组)练习题。

题目链接:P2163 SHOI2007 园丁的烦恼

题目大意

给定平面直角坐标系的 \(n\) 个点,有 \(m\) 次询问,每次询问一个矩形内部(包括边)有多少个点。

\(n, m\le 5\times 10^5\) ,点的横纵坐标 \(0\le x_i, y_i\le 10^7\) ,每个矩形给出其左下顶点 \((a_i, b_i)\) 和右上顶点 \((c_i, d_i)\) 。

解题思路

如果我们可以求出顶点 \((x_i, y_i)\) 的左下方的点的个数 \(f((x_i, y_i))\) ,那么根据前缀和思想,对于一个矩形 \(((a_i, b_i), (c_i, d_i))\):显然会有: \[ans = f((c_i,d_i)) - f((a_i - 1, d_i)) - f((c_i, b_i -1)) + f((a_i - 1, b_i - 1))\]

于是我们就将这个问题转化成了一个求一个点的左下方有多少个点的问题(二维数点问题),考虑怎么来解决它。


二维数点问题

我们考虑离线,我们把所有的询问抽象成对应的点,加上坐标系中原有的点,一起存起来并以 \(x\) 轴的坐标为第一关键字,\(y\) 轴的坐标为第二关键字排序,然后从左往右处理每一个点,这样就可以保证我们在每次询问的时候都只能数到左方的点。

对于 \(y\) 轴方向,我们建立一个树状数组, \(BIT[i]\) ,其原数组为 \(A[i]\) ,表示在当前考虑到的所有的点中,纵坐标不大于 \(i\) 的点有多少个。

在处理点的时候,如果遇到坐标系中原有的点,就可以视为树状数组的修改操作,让 \(A[i]\) 加一;若遇到询问的点,就相当于查询 \(A[1\sim i]\) 的和。

由于树状数组原数组的定义,我们只会数询问的点下方的点,又由于我们按照 \(x\) 轴的方向进行处理,我们只会数到询问的点左方的点,所以我们得到的结果就是查询的点左下方点的个数。


回到原题,我们现在已经求出了每一个点的 \(f((x_i, y_i))\) 值,但是关键是一个矩形对应了四个点,每个点的结果在计算最终答案时加减情况还不同,而且不止一个矩形,我们怎么防止弄混这些呢?

首先,我们可以为每一个点添加一个属性 \(id\) 表示这个点属于第几个矩形,为了便于分辨,我们还可以将原坐标系中的点的 \(id\) 赋值为 \(0\) ,这样,我们就能保证每一个点最多对应一个矩形了。

其次,关于加减的问题,单看一个点我们无从得知它在计算最终答案时是加是减,但是当我们将其放在矩形内看时,我们可以发现,一个矩形左下角和右上角的顶点是加,其他点是减,所以我们可以为每一个点再添加一个属性 \(flag = \pm 1\) 来确定加减,这样当我们在处理单个查询的答案时只需要无脑加即可,当然要乘上 \(flag\) 。

这样,我们便可以得到每一个矩形内有多少个点了。

但是还有一个问题:我们建立的树状数组是建立在纵坐标上的,其下标的值域对应纵坐标的值域,数据范围过大,怎么办?直接对纵坐标进行 离散化

最终代码如下:

#include <cstdio>
#include <algorithm>

const int MAXN = 5e5 + 1;

int n, m, a, b, c, d, cnt;
int res[MAXN * 5];
int BIT[MAXN * 5];
int ans[MAXN];

struct node {
    int num, place;
    node(int nn = 0, int pp = 0) {
        num = nn;
        place = pp;
    }
    bool operator < (const node &another) const {
        return num < another.num;
    }
}temp[MAXN * 5];

struct point {
    int x, y, id, flag;
    point (int xx = 0, int yy = 0, int ii = 0, int ff = 0) {
        x = xx;
        y = yy;
        id = ii;
        flag = ff;
    }
    bool operator < (const point another) const {
        if (x == another.x){
            if (y == another.y)
                return id < another.id;
            else
                return y < another.y;
        }
        else
            return x < another.x;
    }
}arr[MAXN * 5];

void discretizate() {
    std::sort(temp + 1, temp + cnt + 1);
    int cur = 1;
    for (int i = 1; i <= cnt; ++i) {
        res[temp[i].place] = cur;
        if (temp[i].num != temp[i + 1].num)
            ++cur;
    }
    for (int i = 1; i <= cnt; ++i) {
        arr[i].y = res[i];
    }
}

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

void modify(int place, int key) {
    for (; place <= n; place += lowbit(place)) {
        BIT[place] += key;
    }
}

int query(int place) {
    int tmp = 0;
    for (; place; place -= lowbit(place)) {
        tmp += BIT[place];
    }
    return tmp;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d%d", &a, &b);
        arr[++cnt] = point(a, b);
        temp[cnt] = node(b, cnt);
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d%d%d%d", &a, &b, &c, &d); //将一个矩形抽象成四个点加入序列
        arr[++cnt] = point(a - 1, b - 1, i, 1);
        temp[cnt] = node(b - 1, cnt);
        arr[++cnt] = point(a - 1, d, i, -1);
        temp[cnt] = node(d, cnt);
        arr[++cnt] = point(c, b - 1, i, -1);
        temp[cnt] = node(b - 1, cnt);
        arr[++cnt] = point(c, d, i, 1);
        temp[cnt] = node(d, cnt);
    }
    discretizate(); //离散化
    std::sort(arr + 1, arr + cnt + 1);
    for (int i = 1; i <= cnt; ++i) {
        if (arr[i].id == 0)
            modify(arr[i].y, 1);
        else
            ans[arr[i].id] += arr[i].flag * query(arr[i].y);
    }
    for (int i = 1; i <= m; ++i) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

标签:int,题解,id,P2163,MAXN,another,SHOI2007,矩形,我们
来源: https://www.cnblogs.com/lornd/p/11331400.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有