思路:
dp + 线段树优化,和CF985E有类似之处。dp[i][j]表示到第i个Maximizer为止,把最大值移动到第j个位置所需要的最少子序列个数。
实现:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int MAXM = 500005, MAXN = 50005; 5 const int INF = 0x3f3f3f3f; 6 int s[MAXM], t[MAXM], dp[MAXN], tree[MAXN << 2], n, m; 7 void build(int num, int l, int r) 8 { 9 if (l == r) { tree[num] = dp[l]; return; } 10 int m = l + r >> 1; 11 build(num << 1, l, m); 12 build(num << 1 | 1, m + 1, r); 13 tree[num] = min(tree[num << 1], tree[num << 1 | 1]); 14 } 15 void update(int num, int l, int r, int x, int dx) 16 { 17 if (l == r) { tree[num] += dx; return; } 18 int m = l + r >> 1; 19 if (x <= m) update(num << 1, l, m, x, dx); 20 else update(num << 1 | 1, m + 1, r, x, dx); 21 tree[num] = min(tree[num << 1], tree[num << 1 | 1]); 22 } 23 int query(int num, int l, int r, int x, int y) 24 { 25 if (x <= l && y >= r) return tree[num]; 26 int m = l + r >> 1, ans = INF; 27 if (x <= m) ans = min(ans, query(num << 1, l, m, x, y)); 28 if (y >= m + 1) ans = min(ans, query(num << 1 | 1, m + 1, r, x, y)); 29 return ans; 30 } 31 int main() 32 { 33 scanf("%d %d", &n, &m); 34 for (int i = 1; i <= m; i++) scanf("%d %d", &s[i], &t[i]); 35 dp[1] = 0; 36 for (int i = 2; i <= n; i++) dp[i] = INF; 37 build(1, 1, n); 38 for (int i = 1; i <= m; i++) 39 { 40 int tmp = min(dp[t[i]], query(1, 1, n, s[i], t[i]) + 1); 41 update(1, 1, n, t[i], tmp - dp[t[i]]); 42 dp[t[i]] = tmp; 43 } 44 printf("%d ", dp[n]); 45 return 0; 46 }