【集训队互测2015】最大异或和

首先不知道有没有神仙线段树分治过的。

首先一个较为显然的性质:

\[\mathrm{Span}\{v_1, v_2, \dots, v_n\} = \mathrm{Span}\{v_1, v_2 - v_1, \dots, v_n - v_{n - 1}\} \]

这个启发我们维护差分序列,此时1操作变成了单点异或,2操作变成了单点异或以及区间清空。

但是这道题维护的是线性基,所以要用带删除的线性基实现。(具体见【集训队作业2018】围绕着我们的圆环)

此时单点异或显然可以变成插入再删除。因为线性基的时间复杂度,此时暴力清空也没问题。

因为每次操作最多使两个位置非负,暴力清空时特判空向量,此时可以摊还分析,复杂度正确。

因此复杂度为 \(O(\frac{(n+m)mQ}{\omega})\)

这次优化了带删除线性基的代码(从虞大那里参考了部分写法)

#include <bits/stdc++.h>

const int MAXN = 2048;
typedef std::bitset<MAXN> B;
int n, m, Q;
B frm[MAXN], A[MAXN], arr[MAXN];
int bse[MAXN], isb[MAXN];
B read() {
	static B t; t.reset();
	static char buf[MAXN]; std::cin >> buf;
	for (int i = 1; i <= m; ++i) if (buf[i - 1] & 1) t.set(m - i + 1);
	return t;
}
void insert(int at) {
	for (int i = m; i; --i) if (A[at].test(i)) {
		if (bse[i]) A[at] ^= A[bse[i]], frm[at] ^= frm[bse[i]];
		else { isb[bse[i] = at] = i; break; }
	}
}
void modify(int at, B v) {
	if (v.none()) return ;
	int ax = 0; isb[0] = 2001;
	for (int i = 1; i <= n; ++i)
		if (frm[i].test(at))
			isb[i] < isb[ax] ? ax = i : 0;
	for (int i = 1; i <= n; ++i)
		if (i != ax && frm[i].test(at))
			A[i] ^= A[ax], frm[i] ^= frm[ax];
	if (isb[ax]) bse[isb[ax]] = 0, isb[ax] = 0;
	A[ax] ^= v, insert(ax);
}
void output(const B & x) {
	static char buf[MAXN];
	for (int i = 1; i <= m; ++i) buf[i - 1] = x[m - i + 1] + '0';
	std::cout << buf << std::endl;
}
B query() {
	static B t; t.reset();
	for (int i = m; i; --i)
		if (!t.test(i) && bse[i])
			t ^= A[bse[i]];
	return t;
}
int main() {
	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
	std::cin >> n >> m >> Q;
	B t;
	for (int i = 1; i <= n; ++i)
		A[i] = (arr[i] = read()) ^ arr[i - 1], frm[i].set(i), insert(i);
	while (Q --> 0) {
		int opt, t1, t2;
		std::cin >> opt;
		if (opt == 1) {
			std::cin >> t1 >> t2; t = read();
			modify(t1, t);
			if (t2 < n) modify(t2 + 1, t);
			for (int i = t1; i <= t2; ++i) arr[i] ^= t;
		} else if (opt == 2) {
			std::cin >> t1 >> t2; t = read();
			modify(t1, arr[t1] ^ t);
			if (t2 < n) modify(t2 + 1, arr[t2] ^ t);
			for (int i = t1 + 1; i <= t2; ++i)
				modify(i, arr[i] ^ arr[i - 1]);
			for (int i = t1; i <= t2; ++i) arr[i] = t;
		} else if (opt == 3) output(query());
	}
	return 0;
}
posted @ 2019-09-18 22:22  daklqw  阅读(683)  评论(0编辑  收藏  举报