牛客多校 第四场B XOR(模板)

题意:求一个给定n个数组,求下标范围在l和r的数组是否每一个数组都能表示x。

线性基求交。

注意查询时不需要对线性基进行合并。

#include <bits/stdc++.h>
#define lc l,mid,x<<1
#define rc mid+1,r,x<<1|1
using namespace std;
typedef long long LL;
const int maxn = 50005;
const int base = 32;
template <typename T>
struct node
{
    T a[base+1];        //线性基的插入结果
    void init(){
        memset( a,0,sizeof(a) );
    }
    bool ins(T b)         // 向线性基中插入一个数
    {
        for(int i=base;i>=0;i--)
            if(b>>i){
                if(!a[i])
                {
                    a[i]=b;
                    return true ;
                }
                b^=a[i];
            }
        return false ;
    }
    bool check (T b)        // 如果可以表示出来,返回true ,否则返回 false
    {
        for(int i=base;i>=0;i--)
        {
            if(b>>i)
            {
                if(!a[i])return false ;
                b^=a[i];
            }
        }
        return true ;
    }
};
node<LL>tree[maxn*4],tmp,v1;
template <typename  T>
void merge(node<T> &ans,const node<T> &a1,const node<T> &a2 )       // 求 a1,a2的线性基,结果为 ans
{
    tmp=v1 =a1;
    T x,now;
    for(int i=base;i>=0;i--)
    {
        if(!a2.a[i])continue;
        x = a2.a[i],now=0;
        int flag =1 ;
        for(int j=base;j>=0;j--)
        {
            if(x>>j)
            {
                if(!tmp.a[j])
                {
                    flag =0,tmp.a[j]=x,v1.a[j]=now;
                    break;
                }
                x^=tmp.a[j],now^=v1.a[j];
            }
        }
        if(flag)ans.ins(now);
    }
}
void push_up( int x ){
    merge( tree[x],tree[x<<1],tree[x<<1|1] );
}
void build( int l,int r,int x ){
    if( l == r ){
        int sz;LL v;
        scanf("%d",&sz);
        for( int i = 0;i < sz;i++ ){
            scanf("%lld",&v);
            tree[x].ins(v);
        }
        return;
    }
    int mid = l+r>>1;
    build(lc);
    build(rc);
    push_up(x);
}
node<LL> res,c,re;
bool query( int left,int right,LL v,int l,int r,int x ){
    if( left <= l && right >= r ){
        return tree[x].check(v);
    }
    int mid = l+r>>1;
    if( right > mid&&!query(left,right,v,rc) ) return 0;// = query(left,right,rc);
    if( left <= mid && !query(left,right,v,lc) )return 0;// = query(left,right,lc);
    return 1;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    build( 1,n,1 );
    for( int i = 1;i <= m;i++ ){
        LL x;
        int l,r;
        scanf("%d%d%lld",&l,&r,&x);
        bool flag = query( l,r,x,1,n,1 );
        if(!flag ){
            puts("NO");
        }else{
            puts("YES");
        };
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值