题意
给你 $n$ 个集合,每个集合中包含一些整数。我们说一个集合表示一个整数当且仅当存在一个子集其异或和等于这个整数。现在你需要回答 $m$ 次询问 ($l, r, x$),是否 $l$ 到 $r$ 的每个集合都能表示 $x$.
分析
先求出每个集合的线性基,然后用线段树维护线性基的交,详见代码
#include<bits/stdc++.h> #define reg register using namespace std; typedef long long ll; const int bits = 31; const int maxn = 100000 + 10; int n, q; ll a[maxn][32]; struct LBase { //const static int bits = 31; //0~31位 ll d[bits+1], tmp[bits+1]; //线性基 bool flag = false; //记录是否cnt < n LBase() {memset(d, 0, sizeof d);} void insert(ll x) { for(int i=bits;~i;i--) if(x&(1ll<<i)) { if(!d[i]){ d[i]=x; break;} else x ^= d[i]; } flag = true; } bool check(ll x) //返回true表示已经能被表示 { for(int i=bits;~i;i--) if(x&(1ll<<i)) { if(!d[i]) return false; else x ^= d[i]; } return true; } ll qmax(ll res=0) { for(int i=bits;~i;i--) res=max(res,res^d[i]); return res; } ll qmin() { if(flag) return 0; for(int i=0;i<=bits;i++) if(d[i]) return d[i]; } ll query(ll k) //查询第k小 { ll res=0; int cnt=0; k-=flag; if(!k)return 0; for(int i=0;i<=bits;i++){ for(int j=i-1;~j;j--) if(d[i]&(1ll<<j)) d[i]^=d[j]; if(d[i]) tmp[cnt++]=d[i]; } if(k>=(1ll<<cnt))return -1; for(int i=0;i<cnt;i++) if(k&(1ll<<i)) res^=tmp[i]; return res; } void merge(const LBase &a) { //求并集 for (int i = bits; i >= 0; --i) if (a.d[i]) insert(a.d[i]); } }; LBase intersection(const LBase &a,const LBase &b) //求交集 { LBase ans, c=b,d=b; for(int i = 0;i <= bits;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; } struct SegTree { LBase b[maxn << 2]; void build(int o, int L, int R) { int M = L + (R-L) / 2; if(L == R) { for(int i = 0;i < 32;i++) b[o].insert(a[L][i]); } else { build(2*o, L, M); build(2*o+1, M+1, R); //b[o].merge(b[2*o]); b[o].merge(b[2*o+1]); b[o] = intersection(b[2*o], b[2*o+1]); } } //查询[ql, qr]中是否都能表示出x bool query(int o,int L,int R, int ql, int qr, ll x) { int M = L + (R - L) / 2; bool flag1 = true, flag2 = true; if(ql <= L && R <= qr) return b[o].check(x); if(ql <= M) flag1 = query(2*o, L, M, ql, qr, x); if(qr > M) flag2 = query(2*o+1, M+1, R, ql, qr, x); return flag1 && flag2; } }seg; int main(){ scanf("%d%d", &n, &q); for(int i = 1;i <= n;i++) { int sz; scanf("%d", &sz); for(int j = 0;j < sz;j++) scanf("%lld", &a[i][j]); for(int j=sz; j < 32;j++) a[i][j] = 0; } seg.build(1, 1, n); while(q--) { int l, r; ll x; scanf("%d%d%lld", &l, &r, &x); if(seg.query(1, 1, n, l, r, x)) printf("YES\n"); else printf("NO\n"); } return 0; }