题意
分析
就是一个裸的线段树+线性基求交
你问我线性基怎么求交。。。。随便YY了一个
大概的思想就是用B去插 A,如果当前的B消去A后在之前插入的B的张成相同,那么肯定消去的那一部分A的异或和就是一个交
因为线性基每一位只有一个的性质,这样搞完之后肯定线性基还是满足这样的性质
就模板题吧
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 50010;
inline ll read()
{
char ch=getchar(); ll p=0; ll f=1;
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+(ch-'0'); ch=getchar();}
return p*f;
}
ll lc[N<<2],rc[N<<2],rt,tot; ll x[N<<2][33]; ll y[33]; ll id[N];
void build(ll &u,ll L,ll R)
{
if(!u) u = ++tot;
if(L==R){id[L] = u; return ;}
ll mid = (L+R)>>1;
build(lc[u],L,mid);
build(rc[u],mid+1,R);
}
void ins(ll u,ll a)
{
for(ll i=31;i>=0;i--)
{
if(a&(1<<i))
{
if(!x[u][i]){x[u][i] = a; return ;}
else a^=x[u][i];
}
}
}
void merge(ll u,ll lc,ll rc)
{
for(ll i=0;i<=31;i++) x[0][i] = x[lc][i],y[i] = (1<<i);
for(ll i=31;i>=0;i--) if(x[rc][i])
{
ll v = x[rc][i]; ll k = 0; bool can = 1;
for(ll j=31;j>=0;j--) if(v&(1<<j))
{
if(!x[0][j]){x[0][j] = v; y[j] = k; can = 0; break;}
else{v^=x[0][j]; k^=y[j];}
}
if(can)
{
ll s = 0;
for(ll j=31;j>=0;j--) if(k&(1<<j)) s^=x[lc][j];
ins(u,s);
}
}
// printf("%lld\n",u);
// for(ll i=31;i>=0;i--) printf("%lld %lld\n",i,x[u][i]);
}
void dfs(ll u,ll L,ll R)
{
if(L==R) return ;
ll mid=(L+R)>>1;
dfs(lc[u],L,mid); dfs(rc[u],mid+1,R);
merge(u,lc[u],rc[u]);
}
bool qry(ll u,ll L,ll R,ll l,ll r,ll xx)
{
if(L==l && R==r)
{
for(ll i=31;i>=0;i--) if(x[u][i] && (xx&(1<<i))) xx^=x[u][i];
return (xx==0) ? 1 : 0;
}
ll mid=(L+R)>>1;
if(r<=mid) return qry(lc[u],L,mid,l,r,xx);
else if(l>mid) return qry(rc[u],mid+1,R,l,r,xx);
else
{
return qry(lc[u],L,mid,l,mid,xx) & qry(rc[u],mid+1,R,mid+1,r,xx);
}
}
int main()
{
ll n = read(); ll m = read();
rt=tot=0; build(rt,1,n);
for(ll i=1;i<=n;i++)
{
ll k = read();
for(ll j=1;j<=k;j++) ins(id[i],read());
}
dfs(rt,1,n);
for(ll i=1;i<=m;i++)
{
ll l,r,xx; l = read(); r = read(); xx = read();
if(qry(rt,1,n,l,r,xx)) printf("YES\n");
else printf("NO\n");
}
return 0;
}