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';
        }
    }
}
posted @ 2023-12-11 07:35  xlpg0713  阅读(19)  评论(0)    收藏  举报