原题链接:https://www.acwing.com/problem/content/1267/
题目分析
因为y已经排好序了,所以二维问题就转化为一维。
只需要求出每一个x前面有几个小于它的,就是它的级数。
前缀和
考虑前缀和,记录每个位置前面有多少个比他小的星星,s[i] = s[i - 1] + 1;
查询速度 ; 修改速度
我们可以用树状数组求前缀和,查询和修改的时间复杂度均为
(即树状数组的好处是修改操作更快)
树状数组
单点修改
向树状数组中 插/删/改 一个元素,也可以用于线段树的初始化
区间查询
求前缀和 或者 某一段子区间的和
树状数组模板
int lowbit(int x) { return x & -x; } void add(int x, int v) { for (int i = x; i < N; i += lowbit(i)) tr[i] += v ; } int sum(int x) { int res = 0; for (int i = x; i; i -= lowbit(i)) res += tr[i]; return res; }
拓展:树状数组还可以解决区间修改和单点查询
用差分数组,转化为单点修改和区间查询操作
代码细节
- 题目中的x取值从0开始,但是树状数组是从1开始,所以把所有星星的横坐标+1(平移)。
- 输出序列中,每个元素均换行
- 注意level 和add 的顺序:级数不包含当前点所以先写level,在级数更新后再对tr[]更新
- 单点修改操作每次加入一个星星就将对应位置树状数组+1
c++代码
#include<bits/stdc++.h>
using namespace std;
const int N = 32005;
int n;
int tr[N]; //树状数组
int level[N];//每一个级别对应星星的数量
int lowbit(int x)
{
return x & -x;
}
//将x加入到序列中
void add(int x)
{
for (int i = x; i < N; i += lowbit(i))
tr[i] ++ ;
}
//求x对应的级数
int sum(int x)
{
int res = 0;
for (int i = x; i > 0; i -= lowbit(i))
res += tr[i];
return res;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int x, y;
scanf("%d%d", &x, &y);
//平移一个单位使x范围变为1到32001;
x ++ ;
level[sum(x)] ++ ;
add(x);
}
for (int i = 0; i < n; i ++ )
cout << level[i] << endl;
return 0;
}