2019牛客多校第四场B xor(线性基求交)题解

题意:

传送门

\(n\)个集合,每个集合有一些数。给出\(m\)个询问,再给出\(l\)\(r\)和一个数\(v\),问你任意的\(i \in[l,r]\)的集合,能不能找出子集异或为\(v\)。简单点说,\(v\)能用\([l,r]\)任意一个集合的子集异或和表示。

思路:

子集异或和显然是用线性基。我们用线段树维护任意区间的线性基交集即可。

代码:

/**
求交集 O(logn * logn)
**/
LBasis intersection(const LBasis &a, const LBasis &b){
    LBasis ans, c = b, d = b;
    ans.init();
    for (int i = 0; i <= 32; i++){
        ll x = a.d[i];
        if(!x)continue;
        int j = i;
        ll T = 0;
        for(; j >= 0; --j){
            if((x >> j) & 1)
                if(c.d[j]) {x ^= c.d[j]; T ^= d.d[j];}
                else break;
        }
        if(!x) ans.d[i] = T;
        else {c.d[j] = x; d.d[j] = T;}
    }
    return ans;
}
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 50000 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
using namespace std;

struct LBasis{
    ll d[33];
    int tot;
    void init(){
        memset(d, 0, sizeof(d));
        tot = 0;
    }
    bool insert(ll x){
        for(int i = 32; i >= 0; i--){
            if(x & (1LL << i)){
                if(d[i]) x ^= d[i];
                else{
                    d[i] = x;
                    return true;
                }
            }
        }
        return false;
    }

    bool checkin(ll x){
        for(int i = 32; i >= 0; i--){
            if(x & (1LL << i)){
                if(d[i]) x ^= d[i];
                else return false;
            }
        }
        return true;
    }

};
LBasis intersection(const LBasis &a, const LBasis &b){
    LBasis ans, c = b, d = b;
    ans.init();
    for (int i = 0; i <= 32; i++){
        ll x = a.d[i];
        if(!x)continue;
        int j = i;
        ll T = 0;
        for(; j >= 0; --j){
            if((x >> j) & 1)
                if(c.d[j]) {x ^= c.d[j]; T ^= d.d[j];}
                else break;
        }
        if(!x) ans.d[i] = T;
        else {c.d[j] = x; d.d[j] = T;}
    }
    return ans;
}
LBasis node[maxn << 2];
void pushup(int rt){
    node[rt] = intersection(node[rt << 1], node[rt << 1 | 1]);
}
void build(int l, int r, int rt){
    if(l == r){
        int sz;
        scanf("%d", &sz);
        node[rt].init();
        while(sz--){
            ll x;
            scanf("%lld", &x);
            node[rt].insert(x);
        }
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    pushup(rt);
}
bool query(int L, int R, int l, int r, ll v, int rt){
    if(L <= l && R >= r){
        return node[rt].checkin(v);
    }
    int m = (l + r) >> 1;
    bool ok = true;
    if(L <= m)
        ok = ok && query(L, R, l, m, v, rt << 1);
    if(R > m)
        ok = ok && query(L, R, m + 1, r, v, rt << 1 | 1);
    return ok;
}
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    build(1, n, 1);
    while(m--){
        int l, r;
        ll x;
        scanf("%d%d%lld", &l, &r, &x);
        if(query(l, r, 1, n, x, 1)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

posted @ 2019-08-02 15:53  KirinSB  阅读(307)  评论(0编辑  收藏  举报