树状数组-Acwing-1265. 数星星
题目:
天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。
如果一个星星的左下方(包含正左和正下)有 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≤N≤15000,
0≤x,y≤32000
输入样例:
5
1 1
5 1
7 1
3 3
5 5
输出样例:
1
2
1
1
0
题意:
在 平 面 直 角 坐 标 系 中 输 入 N 个 点 的 坐 标 。 规 定 : 某 个 点 的 等 级 l e v e l = 该 点 左 下 方 点 的 个 数 ( 含 正 左 和 正 下 方 的 点 ) 。 在平面直角坐标系中输入N个点的坐标。\\规定:某个点的等级level=该点左下方点的个数(含正左和正下方的点)。 在平面直角坐标系中输入N个点的坐标。规定:某个点的等级level=该点左下方点的个数(含正左和正下方的点)。
输 出 等 级 为 i 的 点 的 数 目 , 0 < = i < = N − 1 。 输出等级为i的点的数目,0<=i<=N-1。 输出等级为i的点的数目,0<=i<=N−1。
题解:
坐 标 的 输 入 是 先 按 纵 坐 标 再 按 横 坐 标 升 序 进 行 的 , 现 要 求 在 当 前 点 的 左 下 方 所 有 点 的 数 量 。 事 实 上 , 就 是 先 输 入 的 点 中 横 坐 标 小 于 当 前 点 的 所 有 点 的 数 量 ( 因 为 当 前 点 的 纵 坐 标 必 然 比 先 前 输 入 的 点 要 大 ) 。 坐标的输入是先按纵坐标再按横坐标升序进行的,现要求在当前点的左下方所有点的数量。事实上,\\就是先输入的点中横坐标小于当前点的所有点的数量(因为当前点的纵坐标必然比先前输入的点要大)。 坐标的输入是先按纵坐标再按横坐标升序进行的,现要求在当前点的左下方所有点的数量。事实上,就是先输入的点中横坐标小于当前点的所有点的数量(因为当前点的纵坐标必然比先前输入的点要大)。
因 为 横 坐 标 的 值 不 是 始 终 递 增 的 , 那 样 就 需 要 边 修 改 边 求 区 间 和 , 动 态 区 间 求 和 用 树 状 数 组 。 因为横坐标的值不是始终递增的,那样就需要边修改边求区间和,动态区间求和用树状数组。 因为横坐标的值不是始终递增的,那样就需要边修改边求区间和,动态区间求和用树状数组。
树 状 数 组 t r [ i ] 维 护 下 标 小 于 等 于 i 的 点 数 量 , 要 求 t r 前 缀 和 即 l e v e l [ i ] 表 示 等 级 为 i 的 点 的 数 量 。 树状数组tr[i]维护下标小于等于i的点数量,要求tr前缀和即level[i]表示等级为i的点的数量。 树状数组tr[i]维护下标小于等于i的点数量,要求tr前缀和即level[i]表示等级为i的点的数量。
时 间 复 杂 度 O ( n l o g 2 n ) , n 是 横 坐 标 范 围 。 时间复杂度O(nlog_2n),n是横坐标范围。 时间复杂度O(nlog2n),n是横坐标范围。
注意:
树 状 数 组 下 标 从 1 开 始 。 树状数组下标从1开始。 树状数组下标从1开始。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define inf 0x7fffffff
using namespace std;
const int N=32010;
int n;
int tr[N];
int level[N];///节点等级
int lowbit(int x)
{
return x&(-x);
}
void add(int w,int p)
{
for(int i=p;i<=N;i+=lowbit(i)) ///N是横坐标上界
tr[i]+=w;
}
int query(int x)///求左下共有多少节点
{
int sum=0;
for(int i=x;i;i-=lowbit(i))
sum+=tr[i];
return sum;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x++;///下标从1开始
level[query(x)]++;///更新节点等级
add(1,x);///x处的数量增加1
}
for(int i=0;i<n;i++) printf("%d\n",level[i]);
return 0;
}