牛客第四场 B xor —— 线性基的交 + 线段树

题目链接:点我啊╭(╯^╰)╮

题目大意:

     n n n 个集合,每次查询一个值,该区间的所有集合都能用子集表示出这个值

解题思路:

    区间每个集合都能表示出一个值,就是线性基的交
    然后用线段树维护一下区间就完事了

核心:线性基求交的模板题

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
ll n, m, a[maxn][40];

struct LB {
	ll cnt, d[35], p[35];
	LB() {
		cnt = 0;
		memset(d,0,sizeof(d));
		memset(p,0,sizeof(p));
	}
	void insert(ll x) {
		for(int i=32; ~i; i--)
			if(x & (1ll<<i)) {
				if(!d[i]) {
					d[i] = x;
					break;
				}
				x ^= d[i];
			}
	}
	bool check(ll x) {
		for(int i=32; ~i; i--)
			if(x & (1ll<<i)) {
				if(!d[i]) return false;
				x ^= d[i];
			}
		return true;
	}
	friend LB merge(const LB &A, const LB &B) {
		LB all, C, D;
		for(int i=32; ~i; i--) {
			all.d[i] = A.d[i];
			D.d[i] = 1ll << i;
		}
		for(int i=32; ~i; i--) {
			if(B.d[i]) {
				ll v = B.d[i], k = 0;
				bool can = true;
				for(int j=32; ~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) {
					v = 0;
					for(int j=32; ~j; j--)
						if(k & (1ll<<j))
							v ^= A.d[j];
					C.insert(v);
				}
			}
		}
		return C;
	}
} t[maxn<<2], s[maxn];

void build(int l,int r,int rt) {
	if(l==r) {
		t[rt] = s[l];
		return ;
	}
	int m = l + r >> 1;
	build(lson);
	build(rson);
	t[rt] = merge(t[rt<<1], t[rt<<1|1]);
}

bool query(int L,int R,int l,int r,int rt,int x) {
	if(L<=l && r<=R) return t[rt].check(x);
	int m = l + r >> 1, res = 1;
	if(L<=m) res = query(L,R,lson,x);
	if(R>m && res) res = query(L,R,rson,x);
	return res;
}

int main() {
	scanf("%d%d", &n, &m);
	for(int i=1, num; i<=n; i++) {
		scanf("%d", &num);
		for(int j=1, x; j<=num; j++)
			scanf("%d", &x), s[i].insert(x);
	}
	build(1,n,1);
	while(m--) {
		ll l, r, x;
		scanf("%d%d%lld", &l, &r, &x);
		if(query(l,r,1,n,1,x)) puts("YES");
		else puts("NO");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值