#include using namespace std; const int N = 1e3 + 10; int n, m; int x[N], y[N]; bool flag; // 当前枚举到的海报是不是能被看到 // 推荐版本:静态离散化+区间覆盖 #define ls (u << 1) #define rs (u << 1 | 1) #define mid ((l + r) >> 1) struct Node { int l, r; bool color; // 是不是所辖区间被完整覆盖 } tr[N << 2]; void pushup(int u) { tr[u].color = tr[ls].color && tr[rs].color; // 只有左儿子被完整覆盖,并且,右儿子被完整覆盖,自己才是被完整覆盖 } void build(int u, int l, int r) { tr[u].l = l, tr[u].r = r; if (l == r) return; build(ls, l, mid); build(rs, mid + 1, r); } void modify(int u, int L, int R) { int l = tr[u].l, r = tr[u].r; if (l > R || r < L) return; if (tr[u].color) return; // 如果本区间原来就已经被覆盖过了,那么返回,也就不会在这段区间使得flag=true,也就是这个区域是看不到的 if (l >= L && r <= R) { // 如果以前没有被覆盖过,并且,本次本区域被完整覆盖,也就是第一次覆盖 flag = true; // 当前枚举到的海报可以被看到 tr[u].color = true; // 记录本区域被完整覆盖 return; } modify(ls, L, R), modify(rs, L, R); pushup(u); } int b[N << 1], bl; // 离散化数组 int main() { #ifndef ONLINE_JUDGE freopen("P3740.in", "r", stdin); #endif // 加快读入 ios::sync_with_stdio(false), cin.tie(0); cin >> n >> m; for (int i = 1; i <= m; i++) { cin >> x[i] >> y[i]; b[++bl] = x[i]; b[++bl] = y[i]; b[++bl] = y[i] + 1; // 区间覆盖问题的解决之道 } // 排序+去重 (要注意b数组的范围,bl代表了它的上界!) sort(b + 1, b + 1 + bl); int tot = unique(b + 1, b + 1 + bl) - b - 1; // 构建线段树 build(1, 1, tot); int res = 0; for (int i = m; i; i--) { // 倒序 flag = false; // 当前枚举到的海报是不是能被看到,默认是不能被看到 int L = lower_bound(b + 1, b + 1 + tot, x[i]) - b; int R = lower_bound(b + 1, b + 1 + tot, y[i]) - b; modify(1, L, R); // 覆盖掉【L,R】 if (flag) res++; // 如果当前枚举到的海报可以被看到,那么多了一张 } // 输出答案 printf("%d\n", res); return 0; }