P11620 [Ynoi Easy Round 2025] TEST_34 Solution

Description

给定长为 n n n 的序列 a = ( a 1 , a 2 , ⋯   , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an),有 m m m 个操作,分以下两种:

  1. modify ⁡ ( l , r , k ) \operatorname{modify}(l,r,k) modify(l,r,k):对于每个 i ∈ [ l , r ] i \in [l,r] i[l,r] 执行 a i ← a i xor ⁡ k a_i \leftarrow a_i \operatorname{xor} k aiaixork
  2. query ⁡ ( l , r , k ) \operatorname{query}(l,r,k) query(l,r,k):求 max ⁡ b ⊆ a l ⋯ r { xor ⁡ j ∈ b j xor ⁡ k } \max\limits_{b \subseteq a_{l\cdots r}} \{ \mathop{\operatorname{xor}}\limits_{j\in b} j \operatorname{xor}k\} balrmax{jbxorjxork}.

Limitations

1 ≤ n , m ≤ 5 × 1 0 4 1 \le n,m \le 5 \times 10^4 1n,m5×104
1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrn
0 ≤ a i , k ≤ 1 0 9 0 \le a_i,k \le 10^9 0ai,k109
3 s , 125 MB 3\text{s},125\text{MB} 3s,125MB

Solution

看到区间最大异或和,想到线段树套线性基.
modify ⁡ \operatorname{modify} modify 操作打不了标记,考虑转化成单点修改.
a a a 差分,设 b 1 = a 1 b_1=a_1 b1=a1 b i = b i − 1 xor ⁡ a i    ( i > 1 ) b_i=b_{i-1} \operatorname{xor} a_i \; (i >1) bi=bi1xorai(i>1)
a i = b 1 xor ⁡ b 2 ⋯ xor ⁡ b i a_i = b_1 \operatorname{xor} b_2 \cdots \operatorname{xor} b_i ai=b1xorb2xorbi.
由异或性质不难发现,从 a l ⋯ r a_{l\cdots r} alr 中选,等价于从 a l , b ( l + 1 ) ⋯ r a_l,b_{(l+1) \cdots r} al,b(l+1)r 中选,因此两者的线性基是等价的.

因此,线段树上只需要维护 b i b_i bi,单点修改,用一个树状数组维护 a i a_i ai 即可。注意特判 l = r l=r l=r 的情况.
时间复杂度 O ( n log ⁡ n log ⁡ 2 V ) O(n\log n \log^2 V) O(nlognlog2V),其中 V V V 为值域.

Code

3.97 KB , 30.78 s , 13.65 MB    (in   total,   C++   20   with   O2) 3.97\text{KB},30.78\text{s},13.65\text{MB} \;\texttt{(in total, C++ 20 with O2)} 3.97KB,30.78s,13.65MB(in total, C++ 20 with O2)
重构了.

// Problem: P5607 [Ynoi2013] 无力回天 NOI2017
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5607
// Memory Limit: 125 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

namespace basis {
	struct Basis {
	    array<int, 31> a;
	    Basis() {}
	    
	    void insert(int x) {
	        for (int i = 30; i >= 0; i--) {
	            if (x & (1 << i)) {
	                if (a[i]) x ^= a[i];
	                else {
	                    a[i] = x;
	                    return;
	                }
	            }
	        }
	    }
	    
	    void clear() { a.fill(0); }
	    
	    int max_xor(int v = 0) {
	        for (int i = 30; i >= 0; i--) 
	            if ((v ^ a[i]) > v) v ^= a[i];
	        return v;
	    }
	    
	};
	
	Basis operator+(const Basis& lhs, const Basis& rhs) {
	    auto res = lhs;
	    for (int i = 30; i >= 0; i--) {
	        if (rhs.a[i]) res.insert(rhs.a[i]);
	    }
	    return res;
	}
}
using basis::Basis;

inline int lowbit(int i) { return i & -i; }
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }

struct SegTree {
    struct Node {
        int l, r;
        Basis bas;
    };
    
    int n;
    vector<Node> tr;
    vector<int> a, c;
    
    SegTree() {}
	SegTree(const vector<int>& _a): a(_a) {
        n = a.size();
        c.resize(n);
        tr.resize(n << 1);
        
        for (int i = n - 1; i >= 1; i--) a[i] ^= a[i - 1];
        for (int i = 0; i < n; i++) add(i, a[i]);
        build(0, 0, n - 1);
    }
    
    inline void add(int x, int v) {
        for (int i = x + 1; i <= n; i += lowbit(i)) c[i - 1] ^= v;
    }
    
    inline int ask(int x) {
        int ans = 0;
        for (int i = x + 1; i; i -= lowbit(i)) ans ^= c[i - 1];
        return ans;
    }
    
    inline void pushup(int u, int mid) {
        tr[u].bas = tr[ls(mid)].bas + tr[rs(mid)].bas;
    }
    
    void build(int u, int l, int r) {
        tr[u].l = l, tr[u].r = r;
        if (l == r) return tr[u].bas.insert(a[l]);
        const int mid = (l + r) >> 1;
        build(ls(mid), l, mid);
        build(rs(mid), mid + 1, r);
        pushup(u, mid);
    }
    
    void update(int u, int p, int v) {
        if (tr[u].l == tr[u].r) {
            tr[u].bas.clear();
            return tr[u].bas.insert(a[p] ^= v);
        }
        const int mid = (tr[u].l + tr[u].r) >> 1;
        if (p <= mid) update(ls(mid), p, v);
        else update(rs(mid), p, v);
        pushup(u, mid);
    }
    
    Basis query(int u, int l, int r) {
        if (l <= tr[u].l && tr[u].r <= r) return tr[u].bas;
        const int mid = (tr[u].l + tr[u].r) >> 1;
        if (r <= mid) return query(ls(mid), l, r);
        else if (l > mid) return query(rs(mid), l, r);
        else return query(ls(mid), l, r) + query(rs(mid), l, r);
    }
    
    inline void range_xor(int l, int r, int v) {
        add(l, v);
        update(0, l, v);
        if (r < n - 1) {
            add(r + 1, v);
            update(0, r + 1, v);
        }
    }
    
    inline int range_maxxor(int l, int r, int v) {
        int k = ask(l);
        if (l == r) return max(k ^ v, v);
        auto cur = query(0, l + 1, r);
        cur.insert(k);
        return cur.max_xor(v);
    }
};

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	scanf("%d %d", &n, &m);
	
	vector<int> a(n);
	for (int i = 0; i < n; i++) scanf("%d", &a[i]);
	
	SegTree sgt(a);
	for (int i = 0, op, l, r, v; i < m; i++) {
	    scanf("%d %d %d %d", &op, &l, &r, &v);
	    l--, r--;
	    
	    if (op == 1) sgt.range_xor(l, r, v);
	    else printf("%d\n", sgt.range_maxxor(l, r, v));
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值