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

题意

在这里插入图片描述

分析

就是一个裸的线段树+线性基求交
你问我线性基怎么求交。。。。随便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;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/98230698
今日推荐