P5313 [Ynoi2011] WBLT 题解

P5313

看到值域比较,又支持离线,可以想到莫队和桶。

考虑先将桶按 b 分段,将每段分别进行按位与运算,做完第 i 段时用于运算的桶全都为 0,就可以直接得到答案。这显然可以用 bitset 优化。但是 STL 的 bitset 不支持分裂操作,所以需要手写。

b 较大时时间复杂度为 O(nm+mVb×bw)(不考虑排序)。

但是发现当 b<w 时时间复杂度是错的,此时就变为了 O(nm+mVb),因为这时候小段太短了,bitset 的压位就失去了作用。

现在考虑 b<64 的情况。

由于 b 很小,考虑对于每一个 b[1,w1]) 做一遍莫队。

这时就只需在 modb 的位置加 1,即维护 b 剩余类。又发现 modb 的值较小,直接对每一个 i 维护其 mex 即可,最后的答案就是 max{mex},对于每一个 imex,依然可以用 bitset 优化。

这一部分的时间复杂度为 O(i=1w1(ncntqi+iVi×1w)),由均值不等式 i=1naini=1nai2n 可得这部分的时间复杂度上界为 O(n×w(cntqi)2w+V),即 O(nmw+V),其中的 w 为常数。

时间复杂度:O(nm+mVw)

代码:

const int N = 1e5 + 10, V = 1e5 + 1, MOD = 63, W = 64, bit = 6;
int n, m, len, cq, nowb;
int a[N], cnt[N], ans[N];
ull filter[W];
struct que {
	int l, r, b, id;
} q[N];
bool cmp(que a, que b) {
	int x = a.l / len, y = b.l / len;
	if (x == y) {
		if (x & 1) return a.r < b.r;
		return a.r > b.r;
	}
	return a.l < b.l;
}
vector<que> qb[W];

struct bitsett {
  int siz;
	vector<ull> v;
	void reset() { for (int i = 0; i <= siz; i++) v[i] = 0; }
	void set() { for (int i = 0; i <= siz; i++) v[i] = ~0ull; }
	void set1(int x) { v[x >> bit] |= (1ull << (x & MOD)); }
	void set0(int x) { v[x >> bit] &= (~(1ull << (x & MOD))); }
	void flip() { for (int i = 0; i <= siz; i++) v[i] = ~v[i]; }
	void operator &= (const bitsett &a) { for (int i = 0; i <= siz; i++) v[i] &= a.v[i]; }
	int mex() { for (int i = 0; ; i++) if (~v[i]) return i << bit | __builtin_ctzll(~v[i]); }
	void init(int x) {
		v.resize((x >> bit) + 2);
		siz = x >> bit;
		reset();
	}
	bool any() {
		for (int i = 0; i <= siz; i++) if (v[i]) return 1;
		return 0;
	}
};
bitsett cur, res, bl[1605], blb[W + 5];
void split(int len) {
	for (int i = 0; i <= V / len + 2; i++) bl[i].init(len);
	int ned = bl[0].siz, bg = 0, np = 0, num = 0;
	for (int i = 0; i <= cur.siz; i++)
		if (np == ned) {
			if (bg + (len & MOD) <= MOD) {
				bl[num].v[np] = (cur.v[i] & (filter[bg + (len & MOD) - 1] - (bg ? filter[bg - 1] : 0))) >> bg;
				i--;
			}
			else if (i != cur.siz) {
				bl[num].v[np] = (cur.v[i] >> bg) | ((cur.v[i + 1] & filter[bg + (len & MOD) - MOD]) << (W - bg));
			} else
				bl[num].v[np] = (cur.v[i] >> bg);
			bg = (bg + (len & MOD)) & MOD, np = 0, num++;
		} else {
			if (bg == 0) bl[num].v[np] = cur.v[i];
			else if (i != cur.siz) bl[num].v[np] = (cur.v[i] >> bg) | ((cur.v[i + 1] & filter[bg - 1]) << (W - bg));
			else bl[num].v[np] = cur.v[i] >> bg;
			np++;
		}
}
void add1(int x) {
	cnt[x]++;
	if (cnt[x] == 1) cur.set1(x);
}
void del1(int x) {
	cnt[x]--;
	if (cnt[x] == 0) cur.set0(x);
}
void add2(int x) {
	cnt[x]++;
	if (cnt[x] == 1) blb[x % nowb].set1(x / nowb);
}
void del2(int x) {
	cnt[x]--;
	if (cnt[x] == 0) blb[x % nowb].set0(x / nowb);
}

int main() {
	filter[0] = 1;
	for (int i = 1; i < W; i++) filter[i] = filter[i - 1] + (1ull << i);
	cin >> n; 
	for (int i = 1; i <= n; i++) cin >> a[i];
	cin >> m;
	for (int i = 1, l, r, b; i <= m; i++) {
		cin >> l >> r >> b;
		if (b > 63) q[++cq] = (que){l, r, b, i};
		else qb[b].pb((que){l, r, 0, i});
	}
	len = n / sqrt(cq) + 1;
	sort(q + 1, q + cq + 1, cmp);
	cur.init(V);
	for (int i = 1, l = 1, r = 0; i <= cq; i++) {
		while (l > q[i].l) add1(a[--l]);
		while (r < q[i].r) add1(a[++r]);
		while (l < q[i].l) del1(a[l++]);
		while (r > q[i].r) del1(a[r--]);
		split(q[i].b);
		res.init(q[i].b);
		res.flip();
		for (int j = 0; ; j++) {
			res &= bl[j];
			if (!res.any()) {
				ans[q[i].id] = j;
				break;
			}
		}
	}
	int mxb = 63;
	for (int i = 1; i <= mxb; i++) {
		if (qb[i].size() == 0) continue;
		memset(cnt, 0, sizeof(cnt));
		nowb = i;
		len = n / sqrt(qb[i].size()) + 1;
		sort(qb[i].begin(), qb[i].end(), cmp);
		for (int j = 0; j < i; j++) blb[j].init(V / i + 1);
		for (int j = 0, l = 1, r = 0; j < (int)(qb[i].size()); j++) {
			while (l > qb[i][j].l) add2(a[--l]);
			while (r < qb[i][j].r) add2(a[++r]);
			while (l < qb[i][j].l) del2(a[l++]);
			while (r > qb[i][j].r) del2(a[r--]);
			for (int k = 0; k < i; k++)
				ans[qb[i][j].id] = max(ans[qb[i][j].id], blb[k].mex());
		}
	}
	for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
	return 0;
}
posted @   Pengzt  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示