2019牛客暑期多校训练营四 B-xor(线性基求交)

题意:

给出\(n\)个序列从\(1\)\(n\),以及\(m\)个询问,每次询问所有\([l,r]\)区间的序列是否能异或出\(x\)

分析:

对于\([l,r]\)区间序列来说,要判断是不是都能异或出\(x\),可以求出\([l,r]\)区间的序列的线性基的交集,然后在这个交集判断即可,那么:
\(n\)个序列的线性基建线段树,pushup时对左右叶子做一次线性基求交。
询问用线段树判断区间交的线性基能否插入\(x\),如果能插入则说明这段区间无法异或出\(x\),反之可以。

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

const int N = 50000 + 5;

struct Base {
    
    static const int maxN = 31;//int-31 or long long-62
    
    int tot, flag;
    int d[maxN + 5];
    int nd[maxN + 5];//used for kth
    
    Base() {
        tot = flag = 0;
        memset(d, 0, sizeof d);
        memset(nd, 0, sizeof nd);
    }

    bool ins(LL x) {
        for (int i = maxN; ~i; i--) {
            if (x & (1LL << i)) {
                if (d[i]) {
                    x ^= d[i];
                } else {
                    d[i] = x;
                    return true;
                }
            }
        }
        flag = 1;
        return false;
    }
    
    bool canIns(LL x) {
        for (int i = maxN; ~i; i--) {
            if (x & (1LL << i)) {
                if (d[i]) {
                    x ^= d[i];
                } else {
                    return true;
                }
            }
        }
        return false;
    }

    LL queryMax() {
        LL ans = 0;
        for (int i = maxN; ~i; i--) ans = max(ans, ans ^ d[i]);
        return ans;
    }

    LL queryMin() {
        for (int i = 0; i <= maxN; i++) if (d[i]) return d[i];
        return -1LL;
    }

    void rebuild() {
        for (int i = maxN; ~i; i--) {
            for (int j = i - 1; ~j; j--) {
                if (d[i] & (1LL << j)) d[i] ^= d[j];
            }
        }
        for (int i = 0; i <= maxN; i++) if (d[i])
                nd[tot++] = d[i];
    }

    LL kth(LL k) {
        if (flag) k--;
        if (!k) return 0LL;
        if (k >= (1LL << tot)) return -1LL;
        LL ans = 0;
        for (int i = maxN; ~i; i--) {
            if (k & (1LL << i)) ans ^= nd[i];
        }
        return ans;
    }

    void merge(Base b) {//与b取并集
        for (int i = maxN; ~i; i--) if (b.d[i])
                ins(b.d[i]);
    }

    Base mixed(Base B) {//与b取交集
        Base All, C, D;
    //  All.init(), C.init(), D.init();
        for (int i = maxN; ~i; i--) {
            All.d[i] = d[i];
            D.d[i] = 1LL << i;
        }
        for (int i = maxN; ~i; i--) {
            if (B.d[i]) {
                LL v = B.d[i], k = 0;
                bool can = true;
                for (int j = maxN; ~j; j--) {
                    if (v & (1LL << j)) {
                        if (All.d[j]) {
                            v ^= All.d[j];
                            k ^= D.d[j];
                        } else {
                            can = false;
                            All.d[j] = v;
                            D.d[j] = k;
                            break;
                        }
                    }
                }

                if (can) {
                    LL v = 0;
                    for (int j = maxN; ~j; j--) {
                        if (k & (1LL << j)) {
                            v ^= d[j];
                        }
                    }
                    C.ins(v);
                }
            }
        }
        return C;
    }

} lb[N << 2];

int n, m, sz, l, r, x;

void build(int rt, int l, int r) {
    if (l == r) {
        scanf("%d", &sz);
        for (int i = 1; i <= sz; i++) {
            scanf("%d", &x);
            lb[rt].ins(x);
        }
        return ;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    lb[rt] = lb[rt << 1].mixed(lb[rt << 1 | 1]);
}

bool query(int rt, int l, int r, int ql, int qr, int w) {
    if (l >= ql && r <= qr) {
        return !lb[rt].canIns(w);
    }
    int mid = l + r >> 1;
    if (ql <= mid && !query(rt << 1, l, mid, ql, qr, w)) return false;
    if (qr > mid && !query(rt << 1 | 1, mid + 1, r, ql, qr, w)) return false;
    return true;
}

int main() {
    scanf("%d %d", &n, &m);
    build(1, 1, n);
    while (m--) {
        scanf("%d %d %d", &l, &r, &x);
        if (x == 0) {
            puts("YES");
            continue;
        }
        if (query(1, 1, n, l, r, x)) puts("YES");
        else puts("NO");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ChaseNo1/p/11750086.html