CCF-CSP认证考试 202303-5 施肥 35/60/75/100分题解

更多 CSP 认证考试题目题解可以前往:CSP-CCF 认证考试真题题解


原题链接: 202303-5 施肥

时间限制: 2.0s
内存限制: 1.0GB

问题描述

春天到了,西西艾弗岛上的 n n n 块田地需要施肥了。 n n n 块田地编号为 1 , 2 , ⋯   , n 1, 2, \cdots, n 1,2,,n,按照编号从小到大的顺序排成一列。

为了给田地施肥,顿顿准备了 m m m 辆施肥车。但是由于土地的松软程度不同,施肥车的质量不一,不一定每一辆施肥车都能给每一块田地施肥。其中,第 i i i 辆施肥车只能恰好从第 l i l_i li 块田地开到第 r i r_i ri 块田地,并给编号在 l i l_i li r i r_i ri 之间的田地(包含 l i l_i li r i r_i ri)都施一遍肥。其中 1 ≤ l i < r i ≤ n 1 \leq l_i < r_i \leq n 1li<rin

顿顿希望制定一个施肥的计划。首先,他将选定二元组 ( L , R ) ( 1 ≤ L < R ≤ n ) (L, R) (1 \leq L < R \leq n) (L,R)(1L<Rn),并选择只给编号在 L , R L, R L,R 之间(包含 L , R L, R L,R)的田地施肥。接着,他会从使用这 m m m 辆施肥车中的一部分(或全部)对田地施肥。他想要保证:编号在 L L L R R R 之内的田地至少被某一辆施肥车施了一次肥,且编号范围外的田地都没有被施过肥。

现在,他想知道,他能够选择多少种不同的二元组 ( L , R ) (L, R) (L,R) 作为施肥范围,使得可以选出一部分(或全部)施肥车,完成他的目标。

输入格式

从标准输入读入数据。

第一行输入两个正整数 n , m n, m n,m,表示田地的块数和 施肥车的辆数。数据保证 2 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ m ≤ 2 ⋅ 1 0 5 2 \leq n \leq 2 \cdot 10^5, 1 \leq m \leq 2 \cdot 10^5 2n2105,1m2105

接下来 m m m 行,第 i i i 行输入两个正整数 l i , r i l_i, r_i li,ri,表示第 i i i 辆施肥车的施肥范围从第 l i l_i li 块田地到第 r i r_i ri 块田地。数据保证 1 ≤ l i < r i ≤ n 1 \leq l_i < r_i \leq n 1li<rin

输出格式

输出到标准输出。

输出一个正整数,表示顿顿能够选择多少种不同的二元组 ( L , R ) (L, R) (L,R) 作为施肥范围,使得他可以选出一部分(或全部)施肥车,完成他的目标。

样例输入1

4 3
1 2
3 4
2 3

样例输出1

6

样例解释

在这组样例中,顿顿可以选择 6 6 6 种不同的二元组 ( L , R ) (L, R) (L,R)

第一种:选择 ( L , R ) = ( 1 , 2 ) (L, R) = (1, 2) (L,R)=(1,2),并只选取第 1 1 1 个施肥车施肥。

第二种:选择 ( L , R ) = ( 3 , 4 ) (L, R) = (3, 4) (L,R)=(3,4),并只选取第 2 2 2 个施肥车施肥。

第三种:选择 ( L , R ) = ( 2 , 3 ) (L, R) = (2, 3) (L,R)=(2,3),并只选取第 3 3 3 个施肥车施肥。

第四种:选择 ( L , R ) = ( 1 , 4 ) (L, R) = (1, 4) (L,R)=(1,4),并选取第 1 1 1 个和第 2 2 2 个施肥车施肥。

第五种:选择 ( L , R ) = ( 1 , 3 ) (L, R) = (1, 3) (L,R)=(1,3),并选取第 1 1 1 个和第 3 3 3 个施肥车施肥。

第六种:选择 ( L , R ) = ( 2 , 4 ) (L, R) = (2, 4) (L,R)=(2,4),并选取第 2 2 2 个和第 3 3 3 个施肥车施肥。

子任务

测试点编号 n ≤ n\le n m ≤ m\le m特殊性质
11818
21818
31818
45050
55050
6400400
7400400
830003000
930003000
1030003000
1130003000
1230003000
13200000200000A
14200000200000A
15200000200000A
16200000200000
17200000200000
18200000200000
19200000200000
20200000200000

特殊性质 A:保证任意两个施肥车的施肥范围不存在相互包含的关系,也就是说,对任意 1 ≤ i < j ≤ m 1 \leq i < j \leq m 1i<jm l i < l j , r i < r j l_i < l_j, r_i < r_j li<lj,ri<rj l i > l j , r i > r j l_i > l_j, r_i > r_j li>lj,ri>rj


35 分题解(测试点 1~7)

对于每组 ( L , R ) (L,R) (L,R),去判断是否能选出若干辆施肥车,使他们的区间并为 [ L , R ] [L,R] [L,R]

选择施肥车的策略是只要满足 L ≤ l i < r i ≤ R L\leq l_i<r_i\leq R Lli<riR 的施肥车就选,选完一辆车就把这辆车能覆盖坐标的 vis + 1 +1 +1,最后判断从 L L L R R R 中的所有坐标是否都是非零。

但是对每一辆车一个个更新速度过慢,考虑差分的算法,如果选 [ l i , r i ] [l_i,r_i] [li,ri] 的这辆车,就将 v i s [ l i ] + 1 , v i s [ r i + 1 ] − 1 vis[l_i]+1,vis[r_i+1]-1 vis[li]+1,vis[ri+1]1,判断完所有车后,直接对 vis 数组求个前缀和即可恢复。

时间复杂度: O ( n 3 + n 2 m ) \mathcal{O}(n^3+n^2m) O(n3+n2m)

35 分参考代码(运行超时,5.050MB)

/*
    Created by Pujx on 2024/3/23.
*/
#pragma GCC optimize(2, 3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
//#define double long double
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
#define inf (int)0x3f3f3f3f3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define yn(x) cout << (x ? "yes" : "no") << endl
#define Yn(x) cout << (x ? "Yes" : "No") << endl
#define YN(x) cout << (x ? "YES" : "NO") << endl
#define mem(x, i) memset(x, i, sizeof(x))
#define cinarr(a, n) for (int i = 1; i <= n; i++) cin >> a[i]
#define cinstl(a) for (auto& x : a) cin >> x;
#define coutarr(a, n) for (int i = 1; i <= n; i++) cout << a[i] << " \n"[i == n]
#define coutstl(a) for (const auto& x : a) cout << x << ' '; cout << endl
#define all(x) (x).begin(), (x).end()
#define md(x) (((x) % mod + mod) % mod)
#define ls (s << 1)
#define rs (s << 1 | 1)
#define ft first
#define se second
#define pii pair<int, int>
#ifdef DEBUG
    #include "debug.h"
#else
    #define dbg(...) void(0)
#endif

const int N = 2e5 + 5;
//const int M = 1e5 + 5;
const int mod = 998244353;
//const int mod = 1e9 + 7;
//template <typename T> T ksm(T a, i64 b) { T ans = 1; for (; b; a = 1ll * a * a, b >>= 1) if (b & 1) ans = 1ll * ans * a; return ans; }
//template <typename T> T ksm(T a, i64 b, T m = mod) { T ans = 1; for (; b; a = 1ll * a * a % m, b >>= 1) if (b & 1) ans = 1ll * ans * a % m; return ans; }

pii a[N];
int n, m, t, k, q;

void work() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) cin >> a[i].ft >> a[i].se;
    int ans = 0;
    for (int l = 1; l <= n; l++)
        for (int r = l + 1; r <= n; r++) {
            vector<int> vis(n + 2);
            for (int i = 1; i <= m; i++)
                if (l <= a[i].ft && a[i].se <= r)
                    vis[a[i].ft]++, vis[a[i].se + 1]--;
            bool flag = true;
            for (int i = l; i <= r; i++)
                flag &= (vis[i] += vis[i - 1]) > 0;
            ans += flag;
        }
    cout << ans << endl;
}

signed main() {
#ifdef LOCAL
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int Case = 1;
    //cin >> Case;
    while (Case--) work();
    return 0;
}
/*
     _____   _   _       _  __    __
    |  _  \ | | | |     | | \ \  / /
    | |_| | | | | |     | |  \ \/ /
    |  ___/ | | | |  _  | |   }  {
    | |     | |_| | | |_| |  / /\ \
    |_|     \_____/ \_____/ /_/  \_\
*/

60 分题解(测试点 1~12)

枚举右端点 R R R,计算有多少个 L L L 满足条件。

1 1 1 m m m 遍历 R R R

a i a_i ai 表示对于每个 i ≤ R i\leq R iR,右端点不大于 R R R 的所有覆盖 i i i 的区间中,左端点的最大值为多少。对每一条右端点为 R R R 的区间 [ l i , R ] [l_i,R] [li,R],用 l i l_i li 更新(取最大值) [ l i , R ] [l_i,R] [li,R] 中的所有 a i a_i ai 即可维护 a i a_i ai

如果 ( L , R ) (L,R) (L,R) 满足条件,当且仅当 ∀ i ∈ [ L , R ] \forall i\in [L,R] i[L,R] a i ≤ L a_i\leq L aiL,即为了覆盖 i i i 这个点,选取的线段的左端点不能比 L L L 小。但要想覆盖到 i i i 这个点,要保证 i + 1 , i + 2 , ⋯   , R i+1,i+2,\cdots,R i+1,i+2,,R 均能被覆盖到,取后缀最小值即可。记 s u f i suf_i sufi 为后缀最小值,即 s u f i = min ⁡ j = i R a i suf_i=\min\limits_{j=i}^Ra_i sufi=j=iminRai

最后,该 R R R 值对答案的贡献为 ∑ i = 1 R [ s u f i = = i ] \sum\limits_{i=1}^R[suf_i==i] i=1R[sufi==i],即 s u f i suf_i sufi i i i 相等的数量。

时间复杂度: O ( n m + n 2 ) \mathcal{O}(nm+n^2) O(nm+n2)

60 分参考代码(运行超时,10.55MB)

/*
    Created by Pujx on 2024/3/23.
*/
#pragma GCC optimize(2, 3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
//#define double long double
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
#define inf (int)0x3f3f3f3f3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define yn(x) cout << (x ? "yes" : "no") << endl
#define Yn(x) cout << (x ? "Yes" : "No") << endl
#define YN(x) cout << (x ? "YES" : "NO") << endl
#define mem(x, i) memset(x, i, sizeof(x))
#define cinarr(a, n) for (int i = 1; i <= n; i++) cin >> a[i]
#define cinstl(a) for (auto& x : a) cin >> x;
#define coutarr(a, n) for (int i = 1; i <= n; i++) cout << a[i] << " \n"[i == n]
#define coutstl(a) for (const auto& x : a) cout << x << ' '; cout << endl
#define all(x) (x).begin(), (x).end()
#define md(x) (((x) % mod + mod) % mod)
#define ls (s << 1)
#define rs (s << 1 | 1)
#define ft first
#define se second
#define pii pair<int, int>
#ifdef DEBUG
    #include "debug.h"
#else
    #define dbg(...) void(0)
#endif

const int N = 2e5 + 5;
//const int M = 1e5 + 5;
const int mod = 998244353;
//const int mod = 1e9 + 7;
//template <typename T> T ksm(T a, i64 b) { T ans = 1; for (; b; a = 1ll * a * a, b >>= 1) if (b & 1) ans = 1ll * ans * a; return ans; }
//template <typename T> T ksm(T a, i64 b, T m = mod) { T ans = 1; for (; b; a = 1ll * a * a % m, b >>= 1) if (b & 1) ans = 1ll * ans * a % m; return ans; }

int a[N], suf[N];
int n, m, t, k, q;
vector<int> R[N];

void work() {
    cin >> n >> m;
    for (int i = 1, l, r; i <= m; i++) {
        cin >> l >> r;
        R[r].emplace_back(l);
    }
    int ans = 0;
    for (int r = 1; r <= n; r++) {
        for (auto l : R[r])
            for (int i = l; i <= r; i++)
                a[i] = max(a[i], l);
        suf[r] = a[r];
        for (int l = r - 1; l; l--)
            ans += (suf[l] = min(suf[l + 1], a[l])) == l;
    }
    cout << ans << endl;
}

signed main() {
#ifdef LOCAL
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int Case = 1;
    //cin >> Case;
    while (Case--) work();
    return 0;
}
/*
     _____   _   _       _  __    __
    |  _  \ | | | |     | | \ \  / /
    | |_| | | | | |     | |  \ \/ /
    |  ___/ | | | |  _  | |   }  {
    | |     | |_| | | |_| |  / /\ \
    |_|     \_____/ \_____/ /_/  \_\
*/

75 分题解(测试点 1~15)

根据题目中给定性质 A 的特殊限制,即给定的区间满足偏序关系,可以将其划分成若干组连续的集合。

在这里插入图片描述

特殊地,如图中的第 5 , 6 5,6 5,6 两条线段,由于田地编号为整数,只要考虑整数是否连续,并不一定要有交集,才可以分在同一组中。

对于每一组来说,只要选择连续(按 l i l_i li 排好序后的序号)的一定数量的线段,即可构成一个不同 ( L , R ) (L,R) (L,R) 组。因此,如果该组有 c n t cnt cnt 个线段,对答案的贡献为 c n t ( c n t + 1 ) 2 \dfrac{cnt(cnt+1)}{2} 2cnt(cnt+1)

时间复杂度:测试点 1 ∼ 12 1\sim 12 112 O ( n m + n 2 ) \mathcal{O}(nm+n^2) O(nm+n2);测试点 13 ∼ 15 13\sim 15 1315 O ( m ) \mathcal{O}(m) O(m)

75 分参考代码(78ms,9.031MB)

/*
    Created by Pujx on 2024/3/23.
*/
#pragma GCC optimize(2, 3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
//#define double long double
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
#define inf (int)0x3f3f3f3f3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define yn(x) cout << (x ? "yes" : "no") << endl
#define Yn(x) cout << (x ? "Yes" : "No") << endl
#define YN(x) cout << (x ? "YES" : "NO") << endl
#define mem(x, i) memset(x, i, sizeof(x))
#define cinarr(a, n) for (int i = 1; i <= n; i++) cin >> a[i]
#define cinstl(a) for (auto& x : a) cin >> x;
#define coutarr(a, n) for (int i = 1; i <= n; i++) cout << a[i] << " \n"[i == n]
#define coutstl(a) for (const auto& x : a) cout << x << ' '; cout << endl
#define all(x) (x).begin(), (x).end()
#define md(x) (((x) % mod + mod) % mod)
#define ls (s << 1)
#define rs (s << 1 | 1)
#define ft first
#define se second
#define pii pair<int, int>
#ifdef DEBUG
    #include "debug.h"
#else
    #define dbg(...) void(0)
#endif

const int N = 2e5 + 5;
//const int M = 1e5 + 5;
const int mod = 998244353;
//const int mod = 1e9 + 7;
//template <typename T> T ksm(T a, i64 b) { T ans = 1; for (; b; a = 1ll * a * a, b >>= 1) if (b & 1) ans = 1ll * ans * a; return ans; }
//template <typename T> T ksm(T a, i64 b, T m = mod) { T ans = 1; for (; b; a = 1ll * a * a % m, b >>= 1) if (b & 1) ans = 1ll * ans * a % m; return ans; }

int a[N], suf[N];
pii v[N];
int n, m, t, k, q;
vector<int> R[N];

void work() {
    cin >> n >> m;
    if (n <= 3000 && m <= 3000) {
        // 测试点 1 ~ 12
        for (int i = 1, l, r; i <= m; i++) {
            cin >> l >> r;
            R[r].emplace_back(l);
        }
        int ans = 0;
        for (int r = 1; r <= n; r++) {
            for (auto l : R[r])
                for (int i = l; i <= r; i++)
                    a[i] = max(a[i], l);
            suf[r] = a[r];
            for (int l = r - 1; l; l--)
                ans += (suf[l] = min(suf[l + 1], a[l])) == l;
        }
        cout << ans << endl;
    }
    else {
        // 测试点 13 ~ 15
        for (int i = 1; i <= m; i++) cin >> v[i].ft >> v[i].se;
        sort(v + 1, v + m + 1);
        i64 ans = 0;
        for (int l = 1, r = 1; l <= m; r = l = r + 1) {
            int rmax = v[l].se;
            while (r + 1 <= m && v[r + 1].ft <= rmax + 1) rmax = max(rmax, v[++r].se);
            int cnt = r - l + 1;
            ans += 1ll * cnt * (cnt + 1) / 2;
        }
        cout << ans << endl;
    }
}

signed main() {
#ifdef LOCAL
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int Case = 1;
    //cin >> Case;
    while (Case--) work();
    return 0;
}
/*
     _____   _   _       _  __    __
    |  _  \ | | | |     | | \ \  / /
    | |_| | | | | |     | |  \ \/ /
    |  ___/ | | | |  _  | |   }  {
    | |     | |_| | | |_| |  / /\ \
    |_|     \_____/ \_____/ /_/  \_\
*/

100 分题解

使用分治算法。通过分治,我们可以得知 [ l , m i d ] , [ m i d + 1 , r ] [l,mid],[mid+1,r] [l,mid],[mid+1,r] 区间内对 ( L , R ) (L,R) (L,R) 总数的贡献,那么仅需要考虑与这两个区间均相交的 ( L , R ) (L,R) (L,R) 的个数。

对于每个 L ∈ [ l , m i d ] L\in[l,mid] L[l,mid],计算出 a L a_L aL 的最大值,满足 [ L , a L ] [L,a_L] [L,aL] 可以由包含于 [ L , m i d ] [L,mid] [L,mid] 的区间取并集得到。

对于每个 R ∈ [ m i d + 1 , r ] R\in[mid+1,r] R[mid+1,r],计算出 b R b_R bR 的最小值,满足 [ b R , R ] [b_R,R] [bR,R] 可以由包含于 [ m i d + 1 , R ] [mid+1,R] [mid+1,R] 的区间取并集得到。

通过两棵线段树维护( A A A 维护数组 a a a B B B 维护数组 b b b),需要单间修改和区间查询最值。实际上 A A A 只用维护最大值, B B B 只用维护最小值,为了写法方便均将最大值和最小值一起维护。

( L , R ) (L,R) (L,R) 如果是一个满足条件的二元组,则横跨两块的区间可以覆盖到 [ a L + 1 , m i d ] [a_L+1,mid] [aL+1,mid] [ m i d + 1 , b R − 1 ] [mid+1,b_R-1] [mid+1,bR1]

对于每个 L ∈ [ l , m i d ] L\in[l,mid] L[l,mid],计算出 x L x_L xL 的最小值,满足 x L ≥ m i d + 1 x_L\geq mid + 1 xLmid+1,且 [ L , x L ] [L,x_L] [L,xL] 可以由包含于 [ L , R ] [L,R] [L,R] 的区间取并集得到(不存在的可以赋为 + ∞ +\infty +)。

对于每个 R ∈ [ m i d + 1 , r ] R\in[mid+1,r] R[mid+1,r],计算出 y R y_R yR 的最大值,满足 y R ≤ m i d y_R\leq mid yRmid,且 [ y R , R ] [y_R,R] [yR,R] 可以由包含于 [ L , R ] [L,R] [L,R] 的区间取并集得到(不存在的可以赋为 − ∞ -\infty )。

  • 通过两棵线段树维护( X X X 维护数组 x x x Y Y Y 维护数组 y y y),需要单间修改和区间查询最值。实际上 X X X 只用维护最小值, Y Y Y 只用维护最大值,为了写法方便均将最大值和最小值一起维护。
  • 由于题目考虑的是整数的区间并而非实数的区间并,在维护线段树 X , Y X,Y X,Y 时(调用 modify 函数)要注意 m i d mid mid 附近的情况,如果写到上一个 ifelse 分支中,会导致后续进行的是实数的区间并(认为整数 m i d mid mid m i d + 1 mid+1 mid+1 无法进行区间并)而造成错误,具体示例可以参考下面这个样例。
    4 2
    1 2
    3 4
    
  • 此外还需要特殊考虑横跨两块的区间对 x , y x,y x,y 的影响(该影响可能不在线段树中体现出来)。

( L , R ) (L,R) (L,R) 所满足的条件可以进一步化为 x L ≤ R , y R ≥ L x_L\leq R,y_R\geq L xLR,yRL,如此变成了一个典型的静态二维数点的问题。

  • ( L , x L ) , ( y R , R ) (L,x_L),(y_R,R) (L,xL),(yR,R) 的满足上述条件的二维点按照左端点值、右端点值、 L , R L,R L,R 的关系进行排序。
  • 采用树状数组(当然也可以使用线段树,只不过不想再写一棵了)维护支持单点修改的区间前缀和。
  • 对于 ( L , x L ) (L,x_L) (L,xL),将 x L x_L xL 的值 + 1 +1 +1
  • 对于 ( y R , R ) (y_R,R) (yR,R),将答案加上 R R R 的前缀和。

注意在线段树/树状数组维护的过程中,要根据区间大小来建立对应大小的线段树/树状数组,或者可以通过清空原有线段树/树状数组,否则可能超时。

时间复杂度: O ( ( n + m ) log ⁡ 2 n ) \mathcal{O}((n+m)\log^2n) O((n+m)log2n)

100 分参考代码(734ms,38.00MB)

/*
    Created by Pujx on 2024/3/23.
*/
#pragma GCC optimize(2, 3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
//#define double long double
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
#define inf (int)0x3f3f3f3f3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define yn(x) cout << (x ? "yes" : "no") << endl
#define Yn(x) cout << (x ? "Yes" : "No") << endl
#define YN(x) cout << (x ? "YES" : "NO") << endl
#define mem(x, i) memset(x, i, sizeof(x))
#define cinarr(a, n) for (int i = 1; i <= n; i++) cin >> a[i]
#define cinstl(a) for (auto& x : a) cin >> x;
#define coutarr(a, n) for (int i = 1; i <= n; i++) cout << a[i] << " \n"[i == n]
#define coutstl(a) for (const auto& x : a) cout << x << ' '; cout << endl
#define all(x) (x).begin(), (x).end()
#define md(x) (((x) % mod + mod) % mod)
#define ls (s << 1)
#define rs (s << 1 | 1)
#define ft first
#define se second
#define pii pair<int, int>
#ifdef DEBUG
    #include "debug.h"
#else
    #define dbg(...) void(0)
#endif

const int N = 2e5 + 5;
//const int M = 1e5 + 5;
const int mod = 998244353;
//const int mod = 1e9 + 7;
//template <typename T> T ksm(T a, i64 b) { T ans = 1; for (; b; a = 1ll * a * a, b >>= 1) if (b & 1) ans = 1ll * ans * a; return ans; }
//template <typename T> T ksm(T a, i64 b, T m = mod) { T ans = 1; for (; b; a = 1ll * a * a % m, b >>= 1) if (b & 1) ans = 1ll * ans * a % m; return ans; }

int a[N], b[N], x[N], y[N];
int n, m, t, k, q;
i64 ans;
vector<int> L[N], R[N];

template <typename T> struct SegmentTree {
    struct TreeNode { int l, r; T mx, mn; } tr[N << 2];
    void pushup(int s) {
        tr[s].mx = max(tr[ls].mx, tr[rs].mx);
        tr[s].mn = min(tr[ls].mn, tr[rs].mn);
    }
    void build(int l, int r, int s = 1) {
        tr[s].l = l, tr[s].r = r;
        tr[s].mx = -inf, tr[s].mn = inf;
        if (l == r) return;
        int mid = l + r >> 1;
        if (l <= mid) build(l, mid, ls);
        if (mid < r) build(mid + 1, r, rs);
        pushup(s);
    }
    void modify(int p, T val, int s = 1) {
        if (tr[s].l == tr[s].r) {
            tr[s].mx = max(tr[s].mx, val);
            tr[s].mn = min(tr[s].mn, val);
            return;
        }
        int mid = tr[s].l + tr[s].r >> 1;
        if (p <= mid) modify(p, val, ls);
        else modify(p, val, rs);
        pushup(s);
    }
    T queryMax(int l, int r, int s = 1) {
        if (l <= tr[s].l && tr[s].r <= r) return tr[s].mx;
        int mid = tr[s].l + tr[s].r >> 1;
        T ans = numeric_limits<T>::min();
        if (l <= mid) ans = max(ans, queryMax(l, r, ls));
        if (mid < r) ans = max(ans, queryMax(l, r, rs));
        return ans;
    }
    T queryMin(int l, int r, int s = 1) {
        if (l <= tr[s].l && tr[s].r <= r) return tr[s].mn;
        int mid = tr[s].l + tr[s].r >> 1;
        T ans = numeric_limits<T>::max();
        if (l <= mid) ans = min(ans, queryMin(l, r, ls));
        if (mid < r) ans = min(ans, queryMin(l, r, rs));
        return ans;
    }
};
SegmentTree<int> A, B, X, Y;

template <typename T> struct Fenwick {
    int n;
    vector<T> a;
    Fenwick(int n = 0) { init(n); }
    void init(int n) { this->n = n; a.assign(n + 1, T()); }
    void add(int x, T v) {
        for (int i = x; i <= n; i += i & -i)
            a[i] += v;
    }
    T sum(int x) {
        auto ans = T();
        for (int i = x; i; i -= i & -i)
            ans += a[i];
        return ans;
    }
    T sum(int l, int r) { return sum(r) - sum(l - 1); }
    void set(int x, T v) { add(x, v - sum(x, x)); }
};
Fenwick<int> fen;

void calc(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    calc(l, mid), calc(mid + 1, r);

    A.build(l, mid), B.build(mid + 1, r), X.build(l, mid + 1), Y.build(mid, r);
    for (int i = l; i <= r; i++) a[i] = y[i] = -inf, b[i] = x[i] = inf;

    for (int i = mid; i >= l; i--)
        for (auto j : L[i]) {
            if (j > r) continue;
            else if (j <= mid) a[i] = max(a[i], j);
            else x[i] = min(x[i], j);
            if (j >= mid) Y.modify(j, i);
        }
    for (int i = mid + 1; i <= r; i++)
        for (auto j : R[i]) {
            if (j < l) continue;
            else if (j >= mid + 1) b[i] = min(b[i], j);
            else y[i] = max(y[i], j);
            if (j <= mid + 1) X.modify(j, i);
        }

    vector<array<int, 3>> v;
    for (int i = mid; i >= l; i--) {
        if (a[i] != -inf) {
            a[i] = max(a[i], A.queryMax(i, min(mid, a[i] + 1)));
            A.modify(i, a[i]);
            x[i] = min(x[i], X.queryMin(i, a[i] + 1));
        }
        if (x[i] != inf) v.push_back({i, x[i], 0});
    }
    for (int i = mid + 1; i <= r; i++) {
        if (b[i] != inf) {
            b[i] = min(b[i], B.queryMin(max(mid + 1, b[i] - 1), i));
            B.modify(i, b[i]);
            y[i] = max(y[i], Y.queryMax(b[i] - 1, i));
        }
        if (y[i] != -inf) v.push_back({y[i], i, 1});
    }

    sort(all(v));
    fen.init(r - l + 1);
    for (auto t : v) {
        if (!t[2]) fen.add(t[1] - l + 1, 1);
        else ans += fen.sum(t[1] - l + 1);
    }
}

void work() {
    cin >> n >> m;
    for (int i = 1, l, r; i <= m; i++) {
        cin >> l >> r;
        L[l].emplace_back(r);
        R[r].emplace_back(l);
    }
    calc(1, n);
    cout << ans << endl;
}

signed main() {
#ifdef LOCAL
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);
    freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int Case = 1;
    //cin >> Case;
    while (Case--) work();
    return 0;
}
/*
     _____   _   _       _  __    __
    |  _  \ | | | |     | | \ \  / /
    | |_| | | | | |     | |  \ \/ /
    |  ___/ | | | |  _  | |   }  {
    | |     | |_| | | |_| |  / /\ \
    |_|     \_____/ \_____/ /_/  \_\
*/

关于代码的亿点点说明:

  1. 代码的主体部分位于 void work() 函数中,另外会有部分变量申明、结构体定义、函数定义在上方。
  2. #pragma ... 是用来开启 O2、O3 等优化加快代码速度。
  3. 中间一大堆 #define ... 是我习惯上的一些宏定义,用来加快代码编写的速度。
  4. "debug.h" 头文件是我用于调试输出的代码,没有这个头文件也可以正常运行(前提是没定义 DEBUG 宏),在程序中如果看到 dbg(...) 是我中途调试的输出的语句,可能没删干净,但是没有提交上去没有任何影响。
  5. ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 这三句话是用于解除流同步,加快输入 cin 输出 cout 速度(这个输入输出流的速度很慢)。在小数据量无所谓,但是在比较大的读入时建议加这句话,避免读入输出超时。如果记不下来可以换用 scanfprintf,但使用了这句话后,cinscanfcoutprintf 不能混用。
  6. main 函数和 work 函数分开写纯属个人习惯,主要是为了多组数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/497064.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt消息机制和事件

Qt消息机制和事件 Qt消息机制和事件--2 事件 事件&#xff08;event&#xff09;是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口需要重新绘制的时候&#xff0c;都会发出一个相应的事件。一些事件在对用户操作做出响应时发出&…

【数据结构】顺序表的实现——静态分配

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;数据结构 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

matplotlib画图:子图中坐标轴与标题重合...

如下图 只要在代码最后加入 plt.tight_layout() 就可以自动调节

江苏开放大学2024年春《市政管理学050011》第一次形考作业参考答案

答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 电大搜题 多的用不完的题库&#xff0c;支持文字、图片搜题…

C语言编译和链接理解

一. 翻译环境和运行环境 二. 翻译环境&#xff1a;预编译编译汇编链接 三运行环境 一. 翻译环境和运行环境 &#xff1a; 1.翻译环境和运行环境&#xff1a;在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。第1种是翻译环境&#xff0c;在这个环境中源代码被转换为…

散热风扇220v交流12v直流12038轴流风机配电箱机柜散热风扇15050

品牌&#xff1a;威驰 颜色分类&#xff1a;11025风扇220v含油,11025风扇220v纯铜双滚珠,12025风扇220v含油,12025风扇220v纯铜双滚珠,12025风扇24V纯铜双滚珠,12025风扇12V纯铜双滚珠,12038风扇220v含油,12038风扇110V含油,12038风扇220v纯铜双滚珠,12038风扇110v纯铜双滚珠,…

如何把PNG图片转换成CAD图纸DWG格式

环境&#xff1a; CAD2021 PNG图片 问题描述&#xff1a; 如何把PNG图片转换成CAD图纸DWG格式 解决方案&#xff1a; 将PNG图像转换为CAD文件&#xff08;如DXF或DWG格式&#xff09;是设计和工程领域中常见的需求之一。幸运的是&#xff0c;有几种工具和软件可以帮助完成…

幻兽帕鲁服务器多少钱?2024年Palworld服务器价格整理

2024年全网最全的幻兽帕鲁服务器租用价格表&#xff0c;阿里云幻兽帕鲁游戏服务器26元1个月、腾讯云32元一个月、京东云26元一个月、华为云24元1个月&#xff0c;阿腾云atengyun.com整理最新幻兽帕鲁专用4核16G、8核16G、8核32G游戏服务器租用价格表大全&#xff1a; 阿里云幻…

Java异常机制

异常体系图 Throwable Throwable 是 Java 语言中所有错误与异常的超类。 Throwable 包含两个子类&#xff1a;Error&#xff08;错误&#xff09;和 Exception&#xff08;异常&#xff09;&#xff0c;它们通常用于指示发生了异常情况。 Throwable 包含了其线程创建时线程执…

计算机组成原理 浮点数溢出

阶码同样有位数限制 浮点数的溢出并不以尾数溢出来判断&#xff0c;尾数溢出可以通过右规操作得到纠正。运算结果是否溢出主要看结果的指数是否发生了上溢&#xff0c;因此是由指数上溢来判断的。可能导致溢出的情况&#xff1a;即所有涉及阶码运算的情况 右规和尾数舍入&…

HBase Shell基本操作

一、进入Hbase Shell客户端 先在Linux Shell命令行终端执行start-dfs.sh脚本启动HDFS&#xff0c;再执行start-hbase.sh脚本启动HBase。如果Linux系统已配置HBase环境变量&#xff0c;可直接在任意目录下执行hbase shell脚本命令&#xff0c;就可进入HBase Shell的命令行终端环…

【JavaWeb】Day22.maven安装介绍

目录 一.初识Maven 什么是maven? Maven的作用 二.Maven概述 1. Maven介绍 2.Maven模型 3. Maven仓库 三. Maven安装 1.下载 2. 安装步骤 1. 解压安装 2. 配置本地仓库 3.配置阿里云私服 4. 配置Maven环境变量 一.初识Maven 什么是maven? Maven是apache旗下的一个…

2024年数字IC秋招-复旦微电子-数字前端/验证-笔试题

文章目录 前言一、基础题/选做题1、什么是DMA&#xff0c;主要优点是什么&#xff0c;为什么这是它的优点2、SV的代码如下&#xff0c;给出$display中变量的值3、列出4bit格雷码编码&#xff0c;画出二进制码转格雷码电路图4、如何从慢时钟域捕获快时钟域脉冲信号&#xff0c;画…

行为管理设置能监控或者检测哪些东西

3 月 27 日&#xff0c;国新办举行“推动高质量发展”系列主题新闻发布会&#xff0c;浙江省省长王浩&#xff1a;全省市场经营主体 1040 万户&#xff0c;相当于平均每 6.5 个浙江人就有 1 个老板。 不由让小编想到&#xff0c;这么多老板&#xff0c;那么老板创办企业也怪不容…

蓝桥杯省三保底代码——数显+按键功能实现

目录 前言 一、为什么能保底省三 二、数显模块的实现 1.数码管显示​编辑 1&#xff09;断码表 2&#xff09;位选 3&#xff09;段选 4&#xff09;扫描 2.菜单 三、按键功能的实现 1.按键扫描 2.菜单切换 四、完整代码演示 五、结语 前言 上一期介绍全家桶时&…

【容器源码篇】Set容器(HashSet,LinkedHashSet,TreeSet的特点)

文章目录 ⭐容器继承关系&#x1f339;Set容器&#x1f5d2;️HashSet源码解析构造方法public HashSet()public HashSet(Collection<? extends E> c)public HashSet(int initialCapacity, float loadFactor)HashSet(int initialCapacity, float loadFactor, boolean dum…

OpenHarmony实战开发-Web组件的使用

介绍 本篇Codelab使用ArkTS语言实现一个简单的免登录过程&#xff0c;向大家介绍基本的cookie管理操作。主要包含以下功能&#xff1a; 获取指定url对应的cookie的值。设置cookie。清除所有cookie。免登录访问账户中心。 原理说明 本应用旨在说明Web组件中cookie的管理操作。…

蓝桥杯_day6

文章目录 不同路径不同路径II拿金币珠宝的最高价值 不同路径 【题目描述】 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为…

主成成分分析法

问题引入&#xff1a; 公司评价 假设你是一个公司的财务经理&#xff0c;掌握了公司所有数据&#xff0c;如:固定资产、流动资金、借贷的数额和期限、各种税费、工资支出、原料消耗、产值、利润、折扣、职工人数、分工和教育程度等等&#xff0c;你要如何选择关键因素进行汇报…

宝宝灯塔:成都辅助生殖市场研究,海外试管成热门

据宝宝灯塔网介绍&#xff1a;在成都的辅助生殖市场中&#xff0c;生殖医院一直是主体&#xff0c;它们提供专业的医疗服务和治疗&#xff0c;帮助不孕不育人群实现生育梦想。然而&#xff0c;随着科技的进步和市场的变化&#xff0c;互联网企业也开始涉足这一领域&#xff0c;…