题目链接
题意:
给出 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);
}
}
}