P5607 && CF587E 题解
题意
转化后的题意都为在序列上的区间异或,查询区间线性基。
题解
先考虑弱化版,\(l=r\),即单点修改。
考虑到一般的线性基支持 \(O(\log v^2)\) 的合并,但是不支持删除,把区间拍到线段树上,单点修改是简单的,直接做就行,加上线段树的一只 \(\log\) 是 \(O((n+q)\times\log_n\times\log_v^2)\),一看数据范围可过。所以考虑怎么把原问题转化成单点修改。
想到了差分 \(b_i=a_i\oplus a_{i-1},b_1=a_1\) 因为有 \(x\oplus y\oplus y=x\) 易于证明 \(a_l\) 到 \(a_r\) 的线性基是 \(a_l\) 与 \(b_{l+1}-b_r\) 的线性基。
到现在就做完了,维护 \(b\) 的线性基,然后就是正常的单点修改了。
代码很好写,不同题略改一下就彳亍了:
#include<iostream>
#include<algorithm>
#include<cstring>
const int N = 5e4 + 10;
struct nd{ int a[35];
void ins(int x){
for(int i = 29; ~i; i--) if(x & (1 << i))
if(a[i]) x ^= a[i]; else return void(a[i] = x);
}
}t[N << 2];
nd mg(nd x, nd y){nd rs = x;
for(int i = 29; ~i; i--)
if(y.a[i]) rs.ins(y.a[i]);
return rs;
}int n, m, a[N], b[N];
inline void is(int p, int x){while(p <= n) b[p] ^= x, p += p & -p;}
inline int qa(int p){int r = 0;while(p) r ^= b[p], p -= p& -p; return r;}
inline void ins(int p, int l, int r){
if(l == r) return t[p].ins(a[l]);
int mid = l + r >> 1;
ins(p * 2, l, mid), ins(p * 2 + 1, mid + 1, r);
t[p] = mg(t[p * 2], t[p * 2 + 1]);
}inline void upd(int p, int l, int r, int x, int k){
if(l == r) return memset(t[p].a, 0, sizeof t[p].a), t[p].ins(a[l] ^= k);
int mid = l + r >> 1; if(x <= mid) upd(p * 2, l, mid, x, k);
else upd(p * 2 + 1, mid + 1, r, x, k); t[p] = mg(t[p * 2], t[p * 2 + 1]);
}inline nd qry(int p, int l, int r, int L, int R){
if(l >= L && r <= R) return t[p];
int mid = l + r >> 1;
if(R <= mid) return qry(p * 2, l, mid, L, R);
if(L > mid) return qry(p * 2 + 1, mid + 1, r, L, R);
return mg(qry(p * 2, l, mid, L, R), qry(p * 2 + 1, mid + 1, r, L, R));
}int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);std::cout.tie(0);
std::cin >> n >> m;
for(int i = 1; i <= n; i++) std::cin >> a[i];
for(int i = n; i > 1; i--) a[i] = a[i] ^ a[i - 1], is(i, a[i]); is(1, a[1]);
ins(1, 1, n); while(m--){ int op, l, r, x; std::cin >> op >> l >> r >> x;
if(op == 1) {is(l, x), upd(1, 1, n, l, x);
if(r < n) is(r + 1, x), upd(1, 1, n, r + 1, x);}
else{
int k = qa(l); if(l == r){std::cout << std::max(k ^ x, x) << '\n'; continue;}
nd o = qry(1, 1, n, l + 1, r); o.ins(k);
for(int i = 29; ~i; i--) if((x ^ o.a[i]) > x) x = x ^ o.a[i];
std::cout << x << '\n';
}
}
}

浙公网安备 33010602011771号