首先不知道有没有神仙线段树分治过的。
首先一个较为显然的性质:
\[ \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;
}