Comet OJ - Contest #3 D可爱的菜菜子(线段树+线性基的合并)

这题其实挺经典的,看到求异或最大,显然想到的是线性基,不过这怎么维护?当然区间有关的东西都可以上线段树,区间修改时记录每个点的修改量k,然后合并线性基时再加入线性基。因为线性基是求一组极大线性无关组,所以查询a[i]^k组成的线性基等价于查询k∪a[i]。

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int N=5e4+7;
struct base{
    int p[32],k;
    void clear(){memset(p,0,sizeof p);}
    void insert(int x)
    {
        for(int i=30;~i;i--)
        if(x>>i&1)
        {
            if(p[i])x^=p[i];
            else{p[i]=x;break;}
        }
    }
    int ask(int x)
    {
        int ret=x;
        for(int i=30;~i;i--)ret=max(ret^p[i],ret);
        return ret;
    }
}tr[N<<2],ans;
int n,m,lazy[N<<2];
base merge(base a,base b)
{
    base ret=a;
    for(int i=30;~i;i--)if(b.p[i])ret.insert(b.p[i]);
    ret.insert(ret.k^b.k);
    return ret;
}
void modify(int rt,int v){tr[rt].k^=v,lazy[rt]^=v;}
void pushdown(int rt){modify(rt<<1,lazy[rt]),modify(rt<<1|1,lazy[rt]),lazy[rt]=0;}
void build(int l,int r,int rt)
{
    if(l==r){scanf("%d",&tr[rt].k);return;}
    int mid=l+r>>1;
    build(lson),build(rson);
    tr[rt]=merge(tr[rt<<1],tr[rt<<1|1]);
}
void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&r<=R){modify(rt,v);return;}
    pushdown(rt);
    int mid=l+r>>1;
    if(L<=mid)update(L,R,v,lson);
    if(R>mid)update(L,R,v,rson);
    tr[rt]=merge(tr[rt<<1],tr[rt<<1|1]);
}
void query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R){ans=merge(ans,tr[rt]);return;}
    pushdown(rt);
    int mid=l+r>>1;
    if(L<=mid)query(L,R,lson);
    if(R>mid)query(L,R,rson);
}
int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while(m--)
    {
        int op,l,r,v;scanf("%d%d%d%d",&op,&l,&r,&v);
        if(op==1)update(l,r,v,1,n,1);
        else ans.clear(),query(l,r,1,n,1),printf("%d\n",ans.ask(v));
    }
}
View Code

 

posted @ 2019-06-15 13:08  hfctf0210  阅读(225)  评论(0编辑  收藏  举报