例题
淘淘摘苹果
讲解
- 由于单调栈在维护时,左儿子会对右儿子有影响,所以有一个 calc 函数,我的 calc 函数传入两个参数,rt 和 val,有一下三种情况
- 如果左儿子的最大值大于 val,那么直接递归左儿子,然后加上右儿子的贡献,因为右儿子的最小值一定大于左儿子的最大值,这是在建树 pushup 时保证的。
- 否则直接递归右儿子,因为左儿子在这时候一定是不满足的,就直接递归右儿子就行。(因为要找的是以val开始的上升序列长度)
- 到叶子节点判断一下和 val 的大小就行。
- pushup 的时候用左儿子和谐一下右儿子,保证单调性。
code
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
const int maxn = 4e5 + 100;
int h[maxn];
int n, m;
struct node { int l, r, maxx, len; } t[maxn];
#define tl t[rt].l
#define tr t[rt].r
#define ls (rt << 1)
#define rs (rt << 1 | 1)
int calc(int rt, int val) {
if (tl == tr) return t[rt].maxx > val;
if (t[ls].maxx > val) return calc(ls, val) + t[rs].len;
else return calc(rs, val);
}
void pushup(int rt) {
t[rt].maxx = max(t[ls].maxx, t[rs].maxx);
t[rs].len = calc(rs, t[ls].maxx);
}
void build(int rt, int l, int r) {
tl = l, tr = r;
if (l == r) return t[rt].maxx = h[l], void();
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(rt);
}
void modify(int rt, int pos) {
if (tl == tr) return t[rt].maxx = h[pos], void();
int mid = (tl + tr) >> 1;
if (pos <= mid) modify(ls, pos);
else modify(rs, pos);
pushup(rt);
}
int main() {
#ifdef debug
#else
freopen("taopapp.in", "r", stdin);
freopen("taopapp.out", "w", stdout);
#endif
n = read(), m = read();
for (int i = 1; i <= n; i++) h[i] = read();
build(1, 1, n);
while (m--) {
int pos = read(), val = read(), tmp = h[pos];
h[pos] = val;
modify(1, pos);
printf("%d
", calc(1, -1));
h[pos] = tmp;
modify(1, pos);
}
return 0;
}