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;
}
posted @ 2019-08-28 19:35  四季夏目天下第一  阅读(117)  评论(0编辑  收藏  举报