8.26 雇佣
题意
给一个长为\(N\)的数列\(a[1]...a[N]\),要求支持如下操作
操作一:给出一个整数\(B\),询问该数列中所有大于等于\(B\)的数能组成多少个极大连续段
操作二:将\(pos\)位上的数改为\(val\)
解法
考场上想出来了...但是由于树状数组没判插入\(0\)的情况,获得了爆零的好成绩
我们可以定义两个相邻数形成的二元组是合法的,当且仅当它们都$\geq B $
可以发现极大连续段的个数就是所有\(\geq B\)的数的个数减去所有合法二元组的个数
这样我们可以开两个树状数组,分别维护这两个值
维护第一个很显然的,把树状数组当成桶插入即可
维护第二个,每次把一个二元组中的最小值插入树状数组即可。在查询时我们查询的是\(\geq B\)的数的个数,可以发现一个二元组中的最小值都大于\(B\)的话,这个二元组中的两个数一定都大于\(B\)
这样计算即可
代码
#include <cstdio>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 4e5 + 10;
int read();
int n, q;
int a[N], b[N];
inline int max(int x, int y) {
return x > y ? x : y;
}
inline int min(int x, int y) {
return x < y ? x : y;
}
struct opt {
int op;
int x, y;
} s[N];
struct BIT {
int c[N];
void insert(int p, int v) {
if (!p) return;
while (p <= b[0]) c[p] += v, p += p & -p;
}
int query(int p) {
int res = 0;
while (p) res += c[p], p -= p & -p;
return res;
}
} tot, nxt;
void discre() {
sort(b + 1, b + b[0] + 1);
b[0] = unique(b + 1, b + b[0] + 1) - b - 1;
for (int i = 1; i <= n; ++i)
a[i] = upper_bound(b + 1, b + b[0] + 1, a[i]) - b - 1;
}
int main() {
freopen("maid.in", "r", stdin);
freopen("maid.out", "w", stdout);
n = read(), q = read();
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i <= n; ++i) b[++b[0]] = a[i];
for (int i = 1; i <= q; ++i) {
s[i].op = read();
if (s[i].op == 1) {
s[i].x = read();
b[++b[0]] = s[i].x;
} else {
s[i].x = read(), s[i].y = read();
b[++b[0]] = s[i].y;
}
}
discre();
for (int i = 1; i <= n; ++i) tot.insert(a[i], 1);
for (int i = 1; i < n; ++i) nxt.insert(min(a[i], a[i + 1]), 1);
for (int i = 1; i <= q; ++i) {
if (s[i].op == 1) {
int val = upper_bound(b + 1, b + b[0] + 1, s[i].x) - b - 1;
printf("%d\n", nxt.query(val - 1) - tot.query(val - 1) + 1);
} else {
int pos = s[i].x, val = upper_bound(b + 1, b + b[0] + 1, s[i].y) - b - 1;
tot.insert(a[pos], -1);
tot.insert(val, 1);
nxt.insert(min(a[pos - 1], a[pos]), -1);
nxt.insert(min(a[pos], a[pos + 1]), -1);
nxt.insert(min(a[pos - 1], val), 1);
nxt.insert(min(val, a[pos + 1]), 1);
a[pos] = val;
}
}
return 0;
}
int read() {
int x = 0, c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
return x;
}