poj1769 Minimizing maximizer

思路:

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\n", dp[n]);
45     return 0;
46 }

猜你喜欢

转载自www.cnblogs.com/wangyiming/p/9077785.html
今日推荐