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)
#endifconst 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 LOCALfreopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endifios::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)
#endifconst 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 LOCALfreopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endifios::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)
#endifconst 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 ~ 12for (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 ~ 15for (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 LOCALfreopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endifios::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)
#endifconst 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 LOCALfreopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.in", "r", stdin);freopen("C:\\Users\\admin\\CLionProjects\\Practice\\data.out", "w", stdout);
#endifios::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.mzph.cn/news/768282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Google云原生工程师的kubernetes最佳实践(二)

目录 二、应用部署篇 为deployment打上丰富的label,以便selecting 使用sidecar容器部署agent、proxy等组件 使用init container处理依赖关系,而不要用sidecar 镜像tag使用版本号,不要用latest或空tag 为pod设置readiness和liveness探针 不要给所有服务都使用LoadBalance…

【微服务】以模块化单体架构开发微服务应用

目录 推荐超级课程: Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战我们知道,起初,单体应用有显著的优势:它们更容易开发和部署。从开发人员的角度来看,这种简单性是有益的。一切都是集中的,可以快速更新任何部分的业务逻辑并立即看到结果。这种开…

竞赛 python opencv 深度学习 指纹识别算法实现

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python opencv 深度学习 指纹识别算法实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;4分创新点&#xff1a;4分 该项目较为新颖…

ETL数据倾斜与资源优化

1.数据倾斜实例 数据倾斜在MapReduce编程模型中比较常见&#xff0c;由于key值分布不均&#xff0c;大量的相同key被存储分配到一个分区里&#xff0c;出现只有少量的机器在计算&#xff0c;其他机器等待的情况。主要分为JOIN数据倾斜和GROUP BY数据倾斜。 1.1GROUP BY数据倾…

【短接笔记本或者台式机的CMOS针脚解决电脑开机无法启动BIOS无法进入问题】

为什么要执行短接笔记本或者台式机的CMOS针脚操作&#xff1f; 问题&#xff1a;可以解决如下图所示&#xff0c;技嘉小雕主板开机时按delete键无法进入BIOS主板界面&#xff0c;长时间等待之后依然无法进入BIOS主板界面&#xff0c;则判定为主板问题。此时短接CMOS针脚可清空…

nodejs+vue高校工作室管理系统python-flask-django-php

系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方法对高校工作室管理的现状进行系统调查。采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而上”的…

python(django(自动化))之流程接口展示功能前端开发

1、创建模板代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>测试平台</title> </head> <body role"document"> <nav class "navbar n…

Redis - list 列表

前言 列表类似于 Java 中的数组或者顺序表&#xff0c;在 Redis 中&#xff0c;可以对列表两端插⼊&#xff08;push&#xff09;和弹出&#xff08;pop&#xff09;&#xff0c;还可以获取指定范围的元素列表、 获取指定索引下标的元素等。列表是⼀种⽐较灵活的数据结构&#…

(一)基于IDEA的JAVA基础7

关系运算符 运算符 含义 范例 结果 等于 12 false &#xff01; 不等于 1&#xff01;2 true > 大于 1>2 false < 小于 …

微服务(基础篇-001-介绍、Eureka)

目录 认识微服务&#xff08;1&#xff09; 服务架构演变&#xff08;1.1&#xff09; 单体架构&#xff08;1.1.1&#xff09; 分布式架构&#xff08;1.1.2&#xff09; 微服务&#xff08;1.1.3&#xff09; 微服务结构 微服务技术对比 企业需求 SpringCloud(1.2) …

思科网络中DHCP中继的配置

一、什么是DHCP中继&#xff1f;DHCP中继有什么用? &#xff08;1&#xff09;DHCP中继是指一种网络设备或服务&#xff0c;用于在不同的子网之间传递DHCP&#xff08;动态主机配置协议&#xff09;消息。DHCP中继的作用是帮助客户端设备获取IP地址和其他网络配置信息&#x…

jvm底层

逐步细化 静态链接&#xff1a;静态方法(符号引用)替换为内存指针或者句柄直接引用) 动态链接&#xff1a;程序期间将符号引用替换为直接引用 对象头&#xff1a; 指针压缩&#xff1a; -XX:UseCompressedOops 开启指针压缩 减少内存消耗&#xff1b;大指针在主内存 缓存间移…

6.3 BP神经网络

在多层感知器被引入的同时&#xff0c;也引入了一个新的问题&#xff1a;由于隐藏层的预期输出并没有在训练样例中给出&#xff0c;隐藏层结点的误差无法像单层感知器那样直接计算得到。 为了解决这个问题&#xff0c;反向传播&#xff08;BP&#xff09;算法被引入&#xff0…

centos glibc 升级导致系统崩溃

centos 7.9默认的glibc为2.17&#xff0c;因为要安装一些软件&#xff0c;需要升级到glibc 2.18&#xff0c;而从源码进行编译和安装&#xff0c;安装失败&#xff0c;导致系统崩溃。 系统崩溃首先想到的是利用启动盘进行救援&#xff0c;而利用centos 7.9的启动盘始终无法挂载…

【PHP + 代码审计】数组排序算法

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

银行监管报送系统介绍(五):金融统计数据大集中自动化报送系统——PBOC Report

人民银行金融统计数据大集中自动化报送系统&#xff08;简称PBOC Report&#xff09;&#xff0c;是基于现代计算机网络技术应用基础上&#xff0c;由人行总行设置金融统计数据服务器&#xff0c;建立的一个全国统一的金融统计数据库。 人行针对各银行存贷款、中间业务、网点人…

信号处理--基于FBCSP滤波方法的运动想象分类

目录 理论 工具 方法 代码获取 理论 通用空间模式 (CSP) 算法可以用来有效构建最佳空间滤波器区分&#xff0c;然后实现运动想象的数据中的脑电信号的区分。然而&#xff0c;空间滤波器性能的好坏主要取决于其工作频带。如果脑电信号没有经过滤波或者滤波的频带范围不合适…

FPGA使用XADC测量外部模拟输入电压

一、XADC简介 1.1、特性 Xilinx系列的FPGA中都包含了一个内置的XADC&#xff0c;我们可以通过这个XADC进行一些精度不高的外部模拟信号采样以及FPGA片内传感器信号采集。XADC的分辨率为12位&#xff0c;采样率为1MSPS。 1.2、结构框图 两片XADC&#xff0c;ADC A可用于片内…

SpringJPA 做分页条件查询

前言: 相信小伙伴们的项目很多都用到SpringJPA框架的吧,对于单表的增删改查利用jpa是很方便的,但是对于条件查询并且分页 是不是很多小伙伴不经常写到. 今天我整理了一下在这里分享一下. 话不多说直接上代码: Controller: RestController public class ProductInstanceContr…

Apache HTTP服务器(Linux离线编译安装)

Apache HTTP服务器&#xff08;Linux离线编译安装&#xff09; Apache是普通服务器&#xff0c;本身只支持html即普通网页。可以通过插件支持PHP,还可以与Tomcat连通(单向Apache连接Tomcat,就是说通过Apache可以访问Tomcat资源。反之不然)。 Apache和Tomcat都可以做为独立的w…