数星星
天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。
如果一个星星的左下方(包含正左和正下)有 $k$ 颗星星,就说这颗星星是 $k$ 级的。
例如,上图中星星 $5$ 是 $3$ 级的($1,2,4$ 在它左下),星星 $2,4$ 是 $1$ 级的。
例图中有 $1$ 个 $0$ 级,$2$ 个 $1$ 级,$1$ 个 $2$ 级,$1$ 个 $3$ 级的星星。
给定星星的位置,输出各级星星的数目。
换句话说,给定 $N$ 个点,定义每个点的等级是在该点左下方(含正左、正下)的点的数目,试统计每个等级有多少个点。
输入格式
第一行一个整数 $N$,表示星星的数目;
接下来 $N$ 行给出每颗星星的坐标,坐标用两个整数 $x,y$ 表示;
不会有星星重叠。星星按 $y$ 坐标增序给出,$y$ 坐标相同的按 $x$ 坐标增序给出。
输出格式
$N$ 行,每行一个整数,分别是 $0$ 级,$1$ 级,$2$ 级,……,$N−1$ 级的星星的数目。
数据范围
$1 \leq N \leq 15000$,
$0 \leq x,y \leq 32000$
输入样例:
5 1 1 5 1 7 1 3 3 5 5
输出样例:
1 2 1 1 0
解题思路
因为要求二维的和,发现需要用到二维的数据结构。我们想想能不能转为一维的问题。
由于坐标是按照纵坐标递增的顺序给的,所以当前星星的纵坐标一定是已存在的星星纵坐标最大的那个。当前星星后面的所有星星(也就是还没给出的星星),要么比当前这个星星的横坐标大(在当前星星的右边),要么比当前星星的纵坐标大(在当前星星的上面)。因此当前星星左下方区域的星星一定是以前出现过的星星,后面的星星就不用再考虑了。因此我们只需要从前面的星星看一下哪些星星的横坐标以及纵坐标都小于当前的星星。又因为当前星星的纵坐标是最大的,所以前面所有的星星纵坐标一定小于当前星星的纵坐标,所有只需要统计横坐标小于等于当前星星的星星个数。
假设当前星星的横坐标为$x_{i}$,也就是求横坐标在$1 \sim x_{i}$星星的个数。可以发现这是在求一个前缀和。我们用一个数组记录横坐标为$i$的星星的个数,$a \left[ i \right]$表示横坐标为$i$的星星的个数。要求横坐标不超过$x_{i}$星星的个数等价于求$a \left[ 1 \right] + a \left[ 2 \right] + ... +a \left[ x_{i} \right]$。
因为每多一个星星都要对$a \left[ x_{i} \right]$加$1$,因此这是一个动态求前缀和的过程。因此一共有两个操作,一个是给某个坐标加$1$,另一个是求某个区间的前缀和,因此要用到树状数组。
AC代码如下:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int N = 32e3 + 10; 6 7 int tr[N], level[N]; 8 9 int lowbit(int x) { 10 return x & -x; 11 } 12 13 int query(int x) { 14 int ret = 0; 15 for (int i = x; i; i -= lowbit(i)) { 16 ret += tr[i]; 17 } 18 return ret; 19 } 20 21 void add(int x) { 22 for (int i = x; i < N; i += lowbit(i)) { 23 tr[i]++; 24 } 25 } 26 27 int main() { 28 int n; 29 scanf("%d", &n); 30 for (int i = 0; i < n; i++) { 31 int x, y; 32 scanf("%d %d", &x, &y); 33 x++; 34 level[query(x)]++; // query(x)表示求下标为1~x这个区间的和 35 add(x); // 给下标为横坐标为x的星星数量加1 36 } 37 38 for (int i = 0; i < n; i++) { 39 printf("%d\n", level[i]); 40 } 41 42 return 0; 43 }
参考资料
AcWing 1265. 数星星(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/670/
标签:星星,int,纵坐标,横坐标,数星星,坐标,当前 来源: https://www.cnblogs.com/onlyblues/p/15924485.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。