2 条题解

  • 0
    @ 2025-5-25 10:20:28

    下面是一份“扫一遍+树状数组”解法的思路导图,假设你已经熟悉了 Fenwick Tree(树状数组)的「点增/前缀和查」操作:


    一、把“左下”转成「一维前缀」+「扫描」

    1. 题中定义

      每颗星 (xi,yi)(x_i,y_i) 的等级 kk = “落在它左下方的星数”, 即所有满足

      xj ≤ xi, yj ≤ yi

      的点的个数(不包括自己)。

    2. 二维到一维

      • 我们可以先按 yy 从小到大走一遍(输入已经按此顺序给好:先按 yy 升序,同 yy 再按 xx 升序)。
      • 当我们处理到第 ii 颗星时,前面所有已处理的点都自然满足 yjyiy_j \le y_i
      • 只剩下 “xjxix_j \le x_i?” 这一维的判断——这正是一维前缀的问题。

    二、用树状数组做「xx-前缀和」

    • 我们建立一个 Fenwick Tree bit[],下标对应 横坐标 xx(注意把它偏移到 1…MAX 范围内)。
    • 含义:当一颗星被处理(“扫过”)后,就在它的 xx-位置做一个 update(x, +1),表示“该横坐标再也少了一颗星”。
    • 查询:要知道有多少已扫过的星的 xjxix_j \le x_i,直接 qry(x_i) 就能在 O(logX)O(\log X) 内给出答案。

    三、完整流程

    1. 读入 NN 颗星的 (xi,yi)(x_i,y_i),注意输入保证“按 yy 升序,同 yy 再按 xx 升序”。

    2. 初始化:bit[] 全 0,cnt[0..N-1] 全 0。

    3. 按输入顺序 遍历每一颗星 (x,y)(x,y)

      int k = qry(x + 1);   // 先查有多少前面星的 x_j ≤ x
      cnt[k]++;             // 它就是 k 级
      upd(x + 1, +1);       // 然后把自己插入 BIT,以便后面点能查到
      
    4. 最后按 k=0…N-1 输出 cnt[k] 即可。


    四、为什么一定正确?

    • 不漏:因为我们只“扫”一次,每个点入队时前面的所有点恰好是 “yjyiy_j \le y_i” 的全集。
    • 不断:每次 upd(x,+1) 保证后面所有查询都能看到这颗星。
    • 不重:因输入同 (y,x)(y,x) 不重复、且每颗星只处理一次。

    两条原则——扫描维yy查询维 用 Fenwick Tree 管理的 xx 前缀——完美契合题意“左下”区域的定义。

    • 0
      @ 2025-3-24 18:18:12
      #include <bits/stdc++.h>
      using namespace std;
      
      const int MAXX = 32005;     // x 坐标上限 + 安全余量
      const int MAXN = 15005;     // 星星数量上限 + 安全余量
      
      int N;                      // 实际星星数
      int bit[MAXX];              // 树状数组,用于统计 x ≤ 某值 的点数
      int cnt[MAXN];              // cnt[k] = k 级星星的个数
      int xs[MAXN], ys[MAXN];     // 存放每颗星的 x, y 坐标
      
      // lowbit:取最低位的 1
      inline int lowbit(int x) {
          return x & -x;
      }
      
      // 在树状数组 bit 上,对下标 i 加 val(本题 val 恒为 1)
      void upd(int i, int val) {
          for (; i < MAXX; i += lowbit(i)) {
              bit[i] += val;
          }
      }
      
      // 查询 bit 的前缀和,即 sum(bit[1..i])
      int qry(int i) {
          int s = 0;
          for (; i > 0; i -= lowbit(i)) {
              s += bit[i];
          }
          return s;
      }
      
      int main() {
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
      
          cin >> N;
          for (int i = 0; i < N; i++) {
              cin >> xs[i] >> ys[i];
              // 输入保证按 y 升序,同 y 时按 x 升序,无需再排序
          }
      
          // 初始化
          memset(bit, 0, sizeof(bit));
          memset(cnt, 0, sizeof(cnt));
      
          // 按输入顺序“扫”每颗星
          for (int i = 0; i < N; i++) {
              int x = xs[i] + 1;  // 把 x 从 [0..32000] 映射到 [1..32001]
              // 查询有多少星的 x_j ≤ x 且 y_j ≤ 当前 y(因为已按 y 排序)
              int k = qry(x);
              // k 就是当前星的“级别”
              cnt[k]++;
              // 把自己插入结构,后续星可统计到它
              upd(x, 1);
          }
      
          // 输出各级星星的数量:0 级到 N−1 级
          for (int k = 0; k < N; k++) {
              cout << cnt[k] << "\n";
          }
          return 0;
      }
      
      • 1

      信息

      ID
      992
      时间
      250ms
      内存
      64MiB
      难度
      9
      标签
      递交数
      27
      已通过
      3
      上传者