洛谷-P4839 P哥的桶(线段树+线性基)

题目链接
题意:

给出 n n n 个集合,每个集合有一些数, m m m 次操作,操作分为两种

1. 1. 1. 向第 k k k个集合加入数 x x x

2. 2. 2. 查询 [ l , r ] [l,r] [l,r] 集合的数异或和最大。

题解:

看到区间查询和修改,就可以想到线段树,而异或和最大,就可以想到线性基,那么就是线段树+线性基。

每次加入数的时候,就更新包含第 k k k个集合的节点的线性基。

查询操作就是把所有合法节点的线性基再重新拿出来放到数组中,再算一遍线性基。

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e4+5;
typedef long long ll;
struct node
{
    
    
    int l,r;
    int val;
}node[MAXN<<2][31];
int dp[31];
void build(int l,int r,int num)
{
    
    
    for(int i=0;i<=30;i++){
    
    
        node[num][i].l=l;
        node[num][i].r=r;
        node[num][i].val=0;
    }
    if(l==r){
    
    
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
}
void push_up(int num,int x)
{
    
    
    for(int i=30;i>=0;i--){
    
    
        if((x>>i)&1){
    
    
            if(node[num][i].val){
    
    
                x^=node[num][i].val;
            }
            else{
    
    
                node[num][i].val=x;
                break;
            }
        }
    }
}
void updata(int pos,int x,int l,int r,int num){
    
    
    push_up(num,x);
    if(l==r){
    
    
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid){
    
    
        updata(pos,x,l,mid,num<<1);
    }
    else{
    
    
        updata(pos,x,mid+1,r,num<<1|1);
    }
}
void query(int find_left,int find_right,int l,int r,int num)
{
    
    
    if(l>=find_left&&r<=find_right)
    {
    
    
        for(int i=30;i>=0;i--)
        {
    
    
            int x=node[num][i].val;
            if(!x) continue;
            for(int j=30;j>=0;j--){
    
    
                if((x>>j)&1){
    
    
                    if(!dp[j]){
    
    
                        dp[j]=x;
                        break;
                    }
                    else{
    
    
                        x^=dp[j];
                    }
                }
            }
        }
        return ;
    }
    int mid=(l+r)>>1;
    if(find_left<=mid) query(find_left,find_right,l,mid,num<<1);
    if(find_right>=mid+1) query(find_left,find_right,mid+1,r,num<<1|1);
}
int main(){
    
    
    int m,n;
    scanf("%d%d",&m,&n);
    build(1,n,1);
    int op;
    while(m--){
    
    
        scanf("%d",&op);
        if(op==1){
    
    
            int k,x;
            scanf("%d%d",&k,&x);
            updata(k,x,1,n,1);
        }
        else{
    
    
            int l,r;
            scanf("%d%d",&l,&r);
            memset(dp,0,sizeof dp);
            query(l,r,1,n,1);
            int ans=0;
            for(int i=30;i>=0;i--){
    
    
                if((ans^dp[i])>ans) ans^=dp[i];
            }
            printf("%d\n",ans);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45755679/article/details/114938369