P哥的桶(线段树+线性基)

https://www.luogu.org/problem/P4839

 

题目: 有两个操作 1 a b  在a的位置添加b数值  (注意一个位置可以有多个值) 2 a b : 在 a到b的范围任取任意的数值相异或,结果最大。

 

分析:用线段树去维护这个操作合并线性基的操作;时间复杂度O(nlogmlogx)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct LB{
    int a[32];
    void add(int x){
        for(int i=31 ; i>=0 ; i--)
        {
            if(x&(1<<i)){
                if(!a[i]){
                    a[i]=x;
                    return ;
                }
                x^=a[i];
            }
        }
    }
    void add(LB &n){
        for(int i=31 ; i>=0 ; i--)
            if(n.a[i]) add(n.a[i]);
    }
}p[maxn],ans;
void update(int rt , int l , int r , int k , int x){
    p[rt].add(x);
    if(l==r) return;
    int mid=(l+r)>>1;
    if(k<=mid)
        update(rt<<1,l,mid,k,x);
    else
        update(rt<<1|1,mid+1,r,k,x);
}
void query(int rt , int l , int r , int ql , int qr){
    if(ql<=l&&qr>=r){
        ans.add(p[rt]);
        return ;
    }
    int mid=(l+r)>>1;
    if(qr<=mid) query(rt<<1,l,mid,ql,qr);
    else if(mid<ql) query(rt<<1|1,mid+1,r,ql,qr);
    else query(rt<<1,l,mid,ql,mid),query(rt<<1|1,mid+1,r,ql,qr);
}
int main(){
    int n,m;scanf("%d%d",&m,&n);
    for(int i=1 ; i<=m ; i++){
        int op,a,b;
        scanf("%d%d%d",&op,&a,&b);
        if(op==1) update(1,1,n,a,b);///在a位置插b
        else {
            memset(ans.a,0,sizeof(ans.a));
            query(1,1,n,a,b);
            int Max=0;
            for(int i=31 ; i>=0 ; i--)
                if((Max^(ans.a[i]))>Max)
                Max^=ans.a[i];
            printf("%d\n",Max);
        }
    }
    return 0;
}
View Code

 

posted @ 2019-08-12 17:22  shuai_hui  阅读(197)  评论(0编辑  收藏  举报