2023年长沙学院程序设计竞赛(CCSUPC) H.序列MEX (分块 + bitset)

发布时间 2023-06-05 18:02:51作者: qdhys

传送门

优雅,太优雅了

解题思路

因为总和不超过1e5,所以最多枚举到500,不知道为啥500会wa,1010就可以ac。考虑分块,每一块维护一个大小为1010的bitset。然后对于查询块外暴力,块内bitset取|,块内bitset取 | 的时间复杂度为1010 / 64, 感觉很优雅的写法, bitset没咋用过,看到这种写法我大为震惊。

#include <bits/stdc++.h>

const int N = 1e5 + 10;
const int M = 1010;
const int INF = 0x3f3f3f3f;
using ll = long long;
#define rep(i, x, y) for (int i = x; i <= y; i ++)
#define per(i, y, x) for (int i = y; i >= x; i --)
typedef std::pair<int, int> PII;

int n, m;

int a[N];
inline void solve() {
	std::cin >> n >> m;
	
	rep(i, 1, n) std::cin >> a[i];
	int B = sqrt(n) + 1;
	
	std::vector<std::bitset<M>> b(n / B + 1);
	std::vector<std::vector<int>> cnt(n / B + 1, std::vector<int> (M, 0));
	
	rep(i, 1, n) {
		if (a[i] > M - 1) continue;
		int cur = i / B;
		b[cur][a[i]] = 1;
		cnt[cur][a[i]] ++;
	}
	
	while (m --) {
		int op, l, r, x;
		std::cin >> op;
		
		if (op == 1) {
			std::cin >> l >> r;
			std::bitset<M> tmp;
			
			int lb = l / B, rb = r / B;
			
			if (lb == rb) {
				rep(i, l, r)
					if (a[i] < M)
						tmp[a[i]] = 1;
			} else {
				rep(i, l, (lb + 1) * B - 1) 
					if (a[i] < M)
						tmp[a[i]] = 1;
				rep(i, rb * B, r) 
					if (a[i] < M)
						tmp[a[i]] = 1;
				rep(i, lb + 1, rb - 1) 
					tmp |= b[i];
			}
			
			int ans = 0;
			
			while (ans < M && tmp[ans]) ans ++;
			std::cout << ans << '\n';
		} else {
			std::cin >> l >> x;
			int bx = l / B;
			if (a[l] < M)
				if (-- cnt[bx][a[l]] == 0) b[bx][a[l]] = 0;
			if (x < M) 
				if (++ cnt[bx][x] == 1) b[bx][x] = 1;
			a[l] = x;
		}
	}
}

int main() {
   std::ios::sync_with_stdio(false);
   std::cin.tie(0);
   std::cout.tie(0);
   
   int _ = 1;
   //std::cin >> _;
   while (_ --) solve();
   
   return 0;
}