【大联盟】20230517 T2 summer(summer) 题解 P5065 【[Ynoi2014] 不归之人与望眼欲穿的人们】

发布时间 2023-07-08 21:32:43作者: zhaohaikun

大家可以猜猜看为什么有两个标题,因为这个原因本文就不设密码了。

5 月模拟赛,6 月补题,7 月补 sol,不愧是我。

题目描述

link

赛时得分:0/0。

完全不会,暴力都没打。

首先,有个经典结论:前缀 or 只会变化 \(\log\) 次。

我们考虑按 \(B\) 分块。

对于块内的答案,每个点开始只有 \(\log\) 种值,直接全部记录下来,查询时二分下即可。

修改:\(O(B\log a)\)
查询:\(O(B\log n)\)

对于跨块的情况,我们从左到右扫所有块,维护到每个块的 \(log\) 个后缀 or 值。一个块内的所有后缀 or 值是好处理的。对于前面块的后缀 or 值,相当于整体 or 上这个块的 or 值,然后合并时归并即可。

修改:\(O(B\log a)\)
查询:\(O(B\log a)\)

于是,\(B\)\(sqrt{n}\),即可做到 \(O(n\sqrt{n}\log a)\)

代码

需要大力卡常。

#include <bits/stdc++.h>
#define SZ(x) (int) x.size() - 1
#define ms(x, y) memset(x, y, sizeof x)
#define all(x) x.begin(), x.end()
#define F(i, x, y) for (int i = (x); i <= (y); i++)
#define DF(i, x, y) for (int i = (x); i >= (y); i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T> inline void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> inline void chkmin(T &x, T y) { x = min(x, y); }
template <typename T> inline void read(T &x) {
	x = 0; int f = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
constexpr int N = 5e4 + 10, B = 180, w = 29, C = N / B + 10, L = B + 10;
int n, m, a[N], mx[C][L], val[C];
vector <pair <int, int>> v, vv, pre[C], suf[C], cur, cc;
bool tag[C];
void build(int id) {
	val[id] = 0;
	ms(mx[id], 0);
	pre[id].clear(), suf[id].clear();
	int l = (id - 1) * B + 1, r = min(n, id * B);
	v.clear();
	F(i, l, r) {
		val[id] |= a[i];
		if (val[id] != (pre[id].empty() ? 0 : pre[id].back().first)) pre[id].emplace_back(val[id], i);//, cout << id << " " << i << " " << val[id] << endl;
		vv.clear();
		F(j, 0, w)
			if (a[i] & (1 << j)) vv.emplace_back(j, i);
		for (auto [j, k]: v)
			if (!(a[i] & (1 << j))) vv.emplace_back(j, k);
		swap(v, vv);
		int cur = 0;
		for (auto [j, k]: v) chkmax(mx[id][i - k + 1], (cur |= (1 << j)));//, cout << i << " " << j << " " << k << '\n';
	} int t = 0;
	DF(i, r, l)
		if ((t |= a[i]) != (suf[id].empty() ? 0 : suf[id].back().first)) suf[id].emplace_back(t, i);//, cout << id << " " << t << " " << i << " " << a[i] << endl;
	reverse(all(suf[id]));
	F(i, 2, B) chkmax(mx[id][i], mx[id][i - 1]);
}
unordered_map <int, int> mp;
signed main() {
	read(n), read(m);
	F(i, 1, n) read(a[i]);
	int full = (n - 1) / B + 1;
	F(i, 1, full) build(i);
	while (m--) {
		int f, x; read(f), read(x);
		if (f == 1) {
			mp.clear();
			int y; read(y);
			a[x] = y;
			tag[(x - 1) / B + 1] = true;
		} else {
			if (mp[x]) {
				cout << mp[x] << '\n';
				continue;
			}
			// F(i, 1, n) cout << a[i] << " "; cout << endl;
			int ans = n + 1;
			F(i, 1, full) {
				if (tag[i]) build(i), tag[i] = false;
				if (mx[i][B] >= x) chkmin(ans, int(lower_bound(mx[i] + 1, mx[i] + B + 1, x) - mx[i]));
			}
			cur.clear();
			F(i, 1, full) {
				if (cur.size()) {
					int pos = 0;
					for (auto [j, k]: pre[i]) {
						while (pos < SZ(cur) && (j | cur[pos + 1].first) >= x) pos++;
						if ((j | cur[pos].first) >= x) chkmin(ans, k - cur[pos].second + 1);
					}
				}
				for (auto &[j, k]: cur) j |= val[i];
				for (auto [j, k]: cur) {
					if (cc.size() && cc.back().first == j) cc.pop_back();
					cc.emplace_back(j, k);
				} cur.clear(); swap(cur, cc);
				for (auto [j, k]: suf[i]) {
					if (cur.size() && cur.back().first == j) cur.pop_back();
					cur.emplace_back(j, k);
				}
			} cout << (mp[x] = (ans > n ? - 1 : ans)) << '\n';
		}
	}
	return 0;
}