1265. 数星星


题目链接

1265. 数星星
天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。

如果一个星星的左下方(包含正左和正下)有 \(k\) 颗星星,就说这颗星星是 \(k\) 级的。

image

例如,上图中星星 \(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

解题思路

树状数组

由于是按纵坐标为第一关键字排序,横坐标为第二关键字排序,按顺序遍历点,可保证前面的点在当前点的下面,同时如果纵坐标相同,前面的点也只会在左边,所以只需要统计左边有多少点,可利用横坐标作为值域的树状数组统计,另外树状数组下标从 \(1\) 开始,横坐标可能为 \(0\),所以需要偏移一位

  • 时间复杂度:\(O(n(log(3.2e4)))\)

代码

// Problem: 数星星
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1267/
// Memory Limit: 64 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include 
 
//#define int long long
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair PII;
 
template  bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template  bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template  void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=3.2e4+5;
int n,tr[N],res[N];
int ask(int x)
{
    int res=0;
    for(;x;x-=x&-x)res+=tr[x];
    return res;
}
void add(int x,int y)
{
    for(;x