差分

模拟太简单了,我就不说了,直接说差分,适用数据可以开下数组的时候
对于给的左右区间,直接把左端点减1,右端点后面一个点+1。
最后再进行一次求前缀和,即可得到原来的区间各个值,值为0的就是存在树的点,注意一下区间范围

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;
const ll MOD = 1e9 + 7;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; }
inline void write(ll x) { if (!x) { putchar('0'); return; } char F[200]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';     tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;   while (b) { if (b & 1)  ans *= a;       b >>= 1;      a *= a; }   return ans; }   ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline int lowbit(int x) { return x & (-x); }

const int N = 1e4 + 7;
int a[N];

int main() {
    int l = read(), n = read();
    while (n--) {
        --a[read()], ++a[read() + 1];
    }
    for (int i = 1; i <= l; ++i)
        a[i] += a[i - 1];
    int ans = 0;
    for (int i = 0; i <= l; ++i)
        if (!a[i])  ++ans;
    write(ans), putchar(10);
    return 0;
}

离散化

再来看看更大的数据怎么办?如果只有组输入,但是这个时候上面的差分就不适用了,因为你开不下这么大的数组。
这个时候就要用到我们的离散化操作,我们只用记录端点即可,之间的值完全没必要知道,只要找到前缀和是0的区间长度是多少就可以了。
我们用一个数组记录每次的左端点和右端点右边一个的节点,赋值分别为1,和-1,代表区间开始和结束。还要添加一个0点,赋值为0。
这样按照升序排序,这样的话,直接把权值累加,当权值加到1的时候,并且目前处理的是区间的开始端点,那么就表明前面一个区间的结束点到现在的开始点都是存在树的区间,把区间长度累加进答案即可,还有就是最后一个端点的右端点和的距离也要单独再算一次,避免漏加。
代码比较好理解,可以康康代码,雨巨

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;
const ll MOD = 1e9 + 7;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();    return s * w; }
inline void write(ll x) { if (!x) { putchar('0'); return; } char F[200]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline int lowbit(int x) { return x & (-x); }

const int N = 1e4 + 7;

struct Node {
    int pos, val;
    bool operator < (const Node& b) const {
        return pos < b.pos;
    }
}a[N << 1];

int main() {
    int l = read(), m = read();
    for (int i = 1; i <= m; ++i) {
        int x = read(), y = read(); //区间头,区间尾
        a[i * 2 - 1].pos = x;
        a[i * 2 - 1].val = 1;
        a[i * 2].pos = y + 1;
        a[i * 2].val = -1;
    }
    a[0].pos = 0, a[0].val = 0;
    sort(a + 1, a + 2 * m + 1); //值周才发现这个bug,一开始我把起点也放进去排序了
                                   //快排中顺序不能保证前后顺序,如果有1换到起点去了……BUG就出来了
    int ans = 0, sum = 0;
    for (int i = 1; i <= 2 * m; ++i) {
        sum += a[i].val;
        if (sum == 1 and a[i].val == 1) //求和为1,并且当前是区间头
            ans += a[i].pos - a[i - 1].pos;
    }
    ans += l - a[2 * m].pos + 1;
    write(ans), putchar(10);
    return 0;
}