Minimizing maximizer

题目大意

有一条长度为的线段,然后会按照顺序给你条线段(固定起点终点)
问,你按照顺序使用这条线段,最少要多少条才能把整条线段覆盖完
但是题目有一个条件,大概就是这条线段至少与之前的覆盖的线段有一个交点

分析

那么这样的话,就可以设计动态转移方程表示从开始覆盖到的最小代价
然后因为要求了一定与前面的线段有交点,所以方程如下:

表示的是枚举到的是第个线段,而并不是一个二维的
然后直接这样维护,它的时间复杂度是,然后观察到这个是查询的一个区间最小值
就是说这个东西大概可以用一个叫做线段树的数据结构来维护一下,这样下来,时间复杂度就变成了
但是需要注意的是,更新的时候,只需要更新右端点的值,其他地方的值其实是没有用的

Code

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;

inline int __read()
{
    int x(0), t(1);
    char o (getchar());
    while (o < '0' || o > '9') {
        if (o == '-') t = -1;
        o = getchar();
    }
    for (; o >= '0' && o <= '9'; o = getchar()) {
        x = (x << 1) + (x << 3) + (o ^ 48);
    }
    return x * t;
}

int ans[maxn << 2];

void update(int l, int r, int p, int val, int x = 1)
{
    if (l == r) {
        ans[x] = min(ans[x], val);
        return ;
    }
    int mid = (l + r) >> 1;
    if (p <= mid) update(l, mid, p, val, x << 1);
    else update(mid + 1, r, p, val, x << 1 | 1);
    ans[x] = min(ans[x << 1], ans[x << 1 | 1]);
}

int query(int l, int r, int tl, int tr, int x = 1)
{
    if (l >= tl && r <= tr) return ans[x];
    int mid = (l + r) >> 1;
    int res(maxn);
    if (tl <= mid) res = min(res, query(l, mid, tl, tr, x << 1));
    if (tr > mid) res = min(res, query(mid + 1, r, tl, tr, x << 1 | 1));
    return res;
}

signed main()
{
    int n = __read(), m = __read();
    memset (ans, 0x3f, sizeof (ans));
    update(1, n, 1, 0);
    while (m--) {
        int s = __read(), t = __read();
        int upt = query(1, n, s, t);
        update(1, n, t, upt + 1);
    }
    printf ("%d\n", query(1, n, n, n));
}