转载自: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;elsereturn y < another.y;}elsereturn 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);elseans[arr[i].id] += arr[i].flag * query(arr[i].y);}for (int i = 1; i <= m; ++i) {printf("%d\n", ans[i]);}return 0;
}

转载于:https://www.cnblogs.com/lornd/p/11331400.html

题解 P2163 SHOI2007 园丁的烦恼相关推荐

  1. P2163 [SHOI2007]园丁的烦恼(二维数点模板题)

    P2163 [SHOI2007]园丁的烦恼 题意: 在一个二维平面内有一些点,给你一个左上角和右下角的点,问这个范围内有多少点 题解: 二维数点模板题 我们设F(a,b)表示以(0,0)为左下角,(a ...

  2. 洛谷 - P2163 [SHOI2007]园丁的烦恼(不带修二维数点-树状数组/主席树)

    题目链接:点击查看 题目大意:二维平面坐标系中给出 nnn 个坐标点,然后是 mmm 次询问,每次询问需要回答一个闭合矩阵中有多少个点 题目分析:想挂树套树来着,但是复杂度有点大.本题不带修且可以离线 ...

  3. 洛谷 P2163 [SHOI2007]园丁的烦恼 (离线sort,树状数组,解决三维偏序问题)

    P2163 [SHOI2007]园丁的烦恼 题目描述 很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草. 有一天国王漫步在花园 ...

  4. P2163 [SHOI2007]园丁的烦恼 (CDQ 分治)

    P2163 [SHOI2007]园丁的烦恼 注意x = 0 和 y = 0; 题目背景 很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各 ...

  5. [SHOI2007]园丁的烦恼

    裸的二维数点 #include"cstdio" #include"cstring" #include"iostream" #include& ...

  6. bzoj千题计划143:bzoj1935: [Shoi2007]Tree 园丁的烦恼

    http://www.lydsy.com/JudgeOnline/problem.php?id=1935 二维偏序问题 排序x,离散化树状数组维护y #include<cstdio> #i ...

  7. 洛谷 P2163 [SHOI2007]Tree 园丁的烦恼

    此题树状数组卡常好题(滑稽) 题目描述 很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草.有一天国王漫步在花园里,若有所思,他 ...

  8. bzoj1935: [Shoi2007]Tree 园丁的烦恼

    这题本来是想用二维树状数组水的.然后不会动态开数组,所以顺便补了一发cdq. 第一维时间,第二维x,第三维y,(其实我自己的感觉是第一维可以不要的),xy很大so离散化谢谢. 询问拆成4个.大家都懂. ...

  9. bzoj1935 [Shoi2007]Tree 园丁的烦恼 二维偏序

    其实这个题就是一个二维偏序,注意不要往树套树上想了 用容斥求出4个点的偏虚前缀和 保证y<要求点 ,就按y排序,分别处理每个询问点 保证x>要求点,就树状数组求前缀和 码: #includ ...

  10. 【题解】vijos1093 文科生的烦恼

    vijos1093 文科生的烦恼 vijos1093 文科生的烦恼 题目 考点 思路 代码 题目 原题链接 一学期一共有n次文科考试,考试科目有4种,分别为政治.历史.地理和综合.每次考哪一科是不定的 ...

最新文章

  1. feign调用多个服务_Spring Cloud多个微服务之间调用代码实例
  2. 详解LAMP源码编译安装
  3. 追源索骥:透过源码看懂Flink核心框架的执行流程
  4. 访问 GitHub 的速度很慢?试试这几种方法
  5. linux 手机 wlan信号桥,手机WLAN信号桥是什么?WLAN信号的作用和使用方法
  6. ssh(Spring+Spring mvc+hibernate)——EmpController
  7. python什么时候用eval_Python:eval的妙用和滥用
  8. Docker Swarm 进阶:NFS 共享数据卷
  9. linux系统增加内存无法启动,linux – 增加虚拟内存而不增加VmSize
  10. 蓝桥杯2019年第十届C/C++省赛B组第八题-等差数列
  11. elasticdump安装_elasticsearch导入导出工具elasticdump安装和使用小记
  12. 现代控制理论(二)李雅普诺夫稳定性分析
  13. 2021年2月程序员工资统计,平均15144元
  14. 物联网嵌入式高级C语言流行框架、学习路线图
  15. dev-c++为什么使用调试时提示[error]ld returned 1 exit status?
  16. C# 实现实时网速
  17. 快速上手 TypeScript
  18. MySQL + Oracle GoldenGate + OGG Application Adpater
  19. 浅析末端并联端接(转载)
  20. 2022年 清华大学大数据研究中心 | 招募专业实践基地合作单位

热门文章

  1. Github使用技巧
  2. HDU 3197 Game(树删边)
  3. IOCP的Demo及说明
  4. python+django(解决对象编码显示Test Object问题)
  5. Oracle Sys和system用户区别
  6. Java loadlibrary分析及如何unload
  7. 我笑了一天的签名。。。
  8. java位图去重_Redis系列(3) Bloom/BitMap/Geo
  9. 带通滤波器作用和用途_常见低通、高通、带通三种滤波器的工作原理
  10. 获取手机唯一标识插件_非常强大的几款手机浏览器,适用于某些黑科技功能