xor(线性基的合并)

题目链接:https://ac.nowcoder.com/acm/contest/884/B

链接:https://ac.nowcoder.com/acm/contest/884/B
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Your are given n sets.Every set contains some integers.

We say a set can express an integer, only when there exists a subset of the set such that the bitwise-xor of the elements in the subset is equal to that integer.

Now you need to answer m queries. Each query will give you three integers l,r,x and you should answer if for every  i∈[l,r]i \in [l,r]i[l,r] ,the i-th set can express x.

输入描述:

The first line contains two integers n,m.

For each of the following n lines, the first integer sz stands for the size of this set and the following sz integers stand for the elements in this set. The sets are described from number 1 to n.

For each of the following m lines, there're three integers l,r,x that means a query.

输出描述:

For each query, output a line.

If for every i∈[l,r]i \in [l,r]i[l,r] ,the i-th set can express x, you need to print “YES”, and "NO" otherwise.
示例1

输入

复制
1 3
2 1 2
1 1 0
1 1 3
1 1 4

输出

复制
YES
YES
NO

备注:

1≤n,m≤500001 \le n,m \le 500001n,m50000 ,1≤sz≤321 \le sz \le 321sz32,1≤l≤r≤n1 \le l \le r \le n1lrn ,the every integer in input ∈[0,232)\in [0,2^{32})[0,232)。
思路:问一个集合挑选出一些数是否能异或为一个数,显然是线性基。 但是题目要求l,r区间内所有集合都要查询,所以暴力显然行不通
那么区间查询显然会想到线段树,维护区间, 这里介绍一下线性基的交,看了代码,自己也不是很懂。 以后真的碰到要用到线性基的交就只能靠板子了。 线段树维护区间的交
这样就能区间查询是否能异或出某个数了。整体就这样了
线性基合并过程:

看代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn=50000+5;
struct Basis
{
    Basis()
    {
        memset(basis,0,sizeof(basis));
    }
    LL basis[35];

    void Update(LL x)//求线性基
    {
        for(LL i=32;i>=0;i--)
        {
            if(x&(1ll<<i))
            {
                if(!basis[i])
                {
                    basis[i]=x;break;
                }
                x^=basis[i];
            }
        }
    }
    bool Ask(LL x)
    {
        for(LL i=32;i>=0;i--)
        {
            if(x&(1ll<<i))
            {
                if(basis[i]) x^=basis[i];
                else return false;
            }
        }
        return true;
    }
}a[maxn],T[maxn<<2];
void Push_up(LL rt)//线性基的合并
{
    Basis tmp=T[rt<<1],v1=T[rt<<1],v2=T[rt<<1|1];
    for(LL i=0;i<32;i++)
    {
        if(v2.basis[i])
        {
            bool flag=true;
            LL x=v2.basis[i],now=0;
            for(LL j=31;j>=0;j--)
            {
                if(x&(1ll<<j))
                {
                    if(!tmp.basis[j])
                    {
                        flag=false;
                        tmp.basis[j]=x;
                        v1.basis[j]=now;
                        break;
                    }
                    x^=tmp.basis[j];now^=v1.basis[j];
                }
            }
            if(flag) T[rt].Update(now);
        }
    }
}
void Build(LL l,LL r,LL rt)
{
    if(l==r)
    {
        T[rt]=a[l];return ;
    }
    LL mid=(l+r)>>1;
    Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);Push_up(rt);
}

bool Query(LL l,LL r,LL rt,LL L,LL R,LL x)
{
    bool flag=true;
    if(L<=l&&r<=R) return T[rt].Ask(x);
    LL mid=(l+r)>>1;
    if(L<=mid) flag&=Query(l,mid,rt<<1,L,R,x);
    if(R>mid) flag&=Query(mid+1,r,rt<<1|1,L,R,x);
    return flag;
}
int main()
{
    LL N,M;
    cin>>N>>M;
    for(LL i=1;i<=N;i++)
    {
        LL len;cin>>len;
        for(LL j=1;j<=len;j++)
        {
            LL x;cin>>x;a[i].Update(x);
        }
    }
    Build(1,N,1);
    while(M--)
    {
        LL l,r,x;cin>>l>>r>>x;
        if(Query(1,N,1,l,r,x)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
 

猜你喜欢

转载自www.cnblogs.com/caijiaming/p/11263221.html