// 演算法 / Algorithm:
// 1) 按右端點 x_end 由小到大排序 / Sort balloons by right endpoint ascending.
// 2) 貪心掃描：箭放在當前組最小右端點；x_start <= 箭位置就共用，否則開新箭。
//    Greedy scan: arrow at current group's smallest x_end; reuse while x_start <= arrow.

#include <vector>      // std::vector，動態陣列 / dynamic array container
#include <algorithm>   // std::sort

class Solution {
public:
    int findMinArrowShots(std::vector<std::vector<int>>& points) {
        // points.empty() 檢查有沒有氣球。/ Check whether there are no balloons.
        if (points.empty()) return 0;

        // 用 lambda（匿名函數）當比較規則，按右端點 [1] 由小到大。
        // A lambda is an inline function; here it compares two balloons by their x_end.
        // 用 a[1] < b[1] 比較而非相減，避免大數相減溢位。
        // Compare a[1] < b[1] instead of subtracting, to avoid 32-bit overflow.
        std::sort(points.begin(), points.end(),
                  [](const std::vector<int>& a, const std::vector<int>& b) {
                      return a[1] < b[1];   // 右端點較小的排前面 / smaller x_end first
                  });

        int arrows = 1;                     // 至少一支箭 / at least one arrow
        // arrowPos：目前這支箭的位置 = 當前組最小右端點。用 long 防溢位。
        // arrowPos: current arrow position = group's smallest x_end; long for safety.
        long arrowPos = points[0][1];

        // 範圍 for 從第二個氣球開始；這裡用索引以便讀左右端點。
        // Iterate from the second balloon (index-based to read both endpoints).
        for (size_t i = 1; i < points.size(); ++i) {
            // points[i][0] 是左端點 x_start。/ points[i][0] is this balloon's x_start.
            if (points[i][0] > arrowPos) {  // 箭碰不到這個氣球 / arrow can't reach this balloon
                ++arrows;                   // 開新箭 / fire a new arrow
                arrowPos = points[i][1];    // 新箭設在此氣球右端點 / place it at this x_end
            }
            // 否則重疊，被同一支箭爆掉。/ Otherwise it overlaps and is burst for free.
        }

        return arrows;                      // 最少箭數 / minimum number of arrows
    }
};
