题目背景
P哥在IOI取得了金牌,现在他开始找女朋友了!
题目描述
P哥现在有nn个桶,他们排成了一排,这些桶可以装下任意多个女朋友。每个女朋友有一个固定的颜值
P哥时不时地会找新女朋友,并把新找的女朋友丢进某个桶里面。我们用1;k;x1kx来表示P哥找了一个颜值为xx的女朋友,并且丢进了kk号桶里面
P哥每天晚上需要在特定的桶里面找一些女朋友观赏。我们用2;l;r2lr来表示P哥在ll号桶到rr号桶之间找女朋友。P哥希望观赏的女朋友颜值异或和尽可能大。
注意:P哥观赏完这些后会女朋友把它们物归原位
输入格式
第一行两个整数n,mn,m,依次表示P哥的操作次数、这组数据会涉及到的最大编号
接下来nn行,每行三个整数,表示操作。操作格式如题
输出格式
对于每个观赏操作,输出P哥能观赏到的最大颜值异或和
输入输出样例
输入 #1复制
5 3
1 1 2
1 2 3
1 3 4
2 1 2
2 1 3
输出 #1复制
3
7
输入 #2复制
11 10
2 6 9
1 9 1523456696
1 1 1818963290
2 6 7
1 1 102229226
2 1 9
2 3 7
1 5 34895532
1 1 1652480680
1 1 1477666032
2 1 10
输出 #2复制
0
0
1818963290
0
1857442578
说明/提示
对于20%的数据,满足n,m\leq 100n,m≤100
对于40%的数据,满足n,m\leq 1000n,m≤1000
另有20%的数据,所有询问满足l=1,r=ml=1,r=m
对于100%的数据,满足n,m<4e5
单点修改+区间查询:线段树。
区间异或max:线性基。
所以我们用线段树维护线性基即可,但是需要注意,因为线性基push_up很麻烦,所以我们直接标记永久化即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=5e4+10;
int n,m;
struct lb{
int a[32];
inline void insert(int x){
for(int i=31;i>=0;i--){
if(x&(1<<i)){
if(a[i]) x^=a[i];
else{a[i]=x; return ;}
}
}
}
inline void insert(lb &x){
for(int i=31;i>=0;i--) if(x.a[i]) insert(x.a[i]);
}
}t[N<<2],res;
void change(int p,int l,int r,int k,int x){
t[p].insert(x);
if(l==r) return ; int mid=l+r>>1;
if(k<=mid) change(p<<1,l,mid,k,x);
else change(p<<1|1,mid+1,r,k,x);
}
void ask(int p,int l,int r,int ql,int qr){
if(l==ql&&r==qr){res.insert(t[p]); return ;}
int mid=l+r>>1;
if(qr<=mid) ask(p<<1,l,mid,ql,qr);
else if(ql>mid) ask(p<<1|1,mid+1,r,ql,qr);
else ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr);
}
inline int calc(int l,int r){
memset(res.a,0,sizeof res.a);
ask(1,1,m,l,r); int ans=0;
for(int i=31;i>=0;i--){
if((ans^res.a[i])>ans) ans^=res.a[i];
}
return ans;
}
signed main(){
cin>>n>>m;
for(int i=1,op,a,b;i<=n;i++){
scanf("%d %d %d",&op,&a,&b);
if(op==1) change(1,1,m,a,b);
else printf("%d\n",calc(a,b));
}
return 0;
}