区间线性基

概述

首先,区间线性基是可以用猫树在 \(O(n\log ^2n)/O(\log ^2n)\) 的时间内处理的,当然这和本文没有任何关系。

本文将介绍如何在 \(O(n\log n)/O(\log n)\) 的时间复杂度内维护区间线性基。

贪心地维护带权线性基

考虑贪心,直接在插入元素 \(x\) 时,如果线性基 \(b\)\(b_i\) 时有值的,并且权值(即下标)优于 \(x\) 的权值,那么将 \(x\)\(b_i\) 交换,并继续尝试插入此时的 \(x\)(即原先的 \(b_i\))。

容易证明这是对的。

区间线性基

\(\forall i\in [1,n]\),维护包含 \([1,i]\) 的带权线性基,权值为下标。

查询时查 \([1,r]\) 的线性基,跳过所有权值小于 \(l\) 的值。

// ABC233Ex

#include<bits/stdc++.h>

using namespace std;

using ll=long long;
const int N=4e5+9;
const int lgV=60;

struct Basis{
    ll b[lgV];int w[lgV];
    inline void Insert(ll x,int k){
        for(int i=lgV-1;~i;i--){
            if(~x>>i&1) continue ;
            if(k>w[i]){
                swap(b[i],x),swap(w[i],k);
                if(!x) break ;
            }
            x^=b[i];
        }
    }
    inline bool Find(ll x,int k){
        for(int i=lgV-1;~i;i--) if(w[i]>=k&&(x>>i&1)) x^=b[i];
        return !x;
    }
}b[N];

int n,q;
ll a[N];

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    #define endl '\n'

    cin>>n>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=b[i-1];
        b[i].Insert(a[i],i);
    }

    while(q--){
        int l,r;ll x;
        cin>>l>>r>>x;

        if(b[r].Find(x,l)) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }

    return 0;
}

例题

posted @ 2025-03-08 15:31  JoeyJiang  阅读(27)  评论(0)    收藏  举报