There is an integer sequence aa of length n and there are two kinds of operations:
- 0 l r: select some numbers from al...ar so that their xor sum is maximum, and print the maximum value.
- 1 x: append x to the end of the sequence and let n=n+1.
Input
There are multiple test cases. The first line of input contains an integer T(T≤10), indicating the number of test cases.
For each test case:
The first line contains two integers n,m(1≤n≤5×105,1≤m≤5×105), the number of integers initially in the sequence and the number of operations.
The second line contains n integers a1,a2,...,an(0≤ai<230) , denoting the initial sequence.
Each of the next mm lines contains one of the operations given above.
It's guaranteed that ∑n≤106,∑m≤106,0≤x<230.
And operations will be encrypted. You need to decode the operations as follows, where lastans denotes the answer to the last type 0 operation and is initially zero:
For every type 0 operation, let l=(l xor lastans)mod n + 1, r=(r xor lastans)mod n + 1, and then swap(l, r) if l>r.
For every type 1 operation, let x=x xor lastans.
Output
For each type 0 operation, please output the maximum xor sum in a single line.
Sample Input
1
3 3
0 1 2
0 1 1
1 3
0 3 4
Sample Output
1
3
题意:
给n个数,m个询问,每次询问有两种0 l r,代表查询(l^ans)%n+1到(r^ans)%n+1区间内这些数中选一部分异或的最大值(放在ans中),1 x代表在序列末尾加入一个数x^ans。
思路:
当时在比赛时想过线性基,但是感觉暴力的话时间复杂度比较高。结束后跟同学讨论,得知有另一种构造线性基的方式(参考 51-nod 1577)。构造思路,对于每一个数构造一个线性基,这个线性基是以他为结尾,选他之前的并且最靠近他的元素构造的。构造方式是,从左向右遍历数组,把第一个元素加入第一个线性基中,然后之后的线性基先继承前一个线性基,然后再往其中加入当前位置的元素。不过这里加元素和普通的线性基有些不同,这里需要维护每一位的加入的元素的位置即代码中的idx数组。加入新元素时,如果当前位置没有元素,则直接加入,如果有元素,并且这个元素加入时间比当前元素早,就将d数组中的元素和当前要继续插入的元素交换,顺便交换加入时间。然后继续把这个元素看看能不能在后面的位置插入进去。
查找最大值和之前的查找方式差不多,只不过需要先固定右端点,这样就保证选的元素都是在右端点左边的,然后贪心选的元素的同时,需要看看这个元素是不是在左区间的右边即可。加入新的元素时需要为其构建一个新的线性基,构造方式同上。
这里需要注意对线性基数组的初始化,因为T组样例,所以只需要将lb[0]初始化,后面的是在继承前面的基础上,在加元素的。并且这里读入要从1~n读,因为后面询问的l,r是1~n的。因为是在原数组的结尾加元素,所以构造线性基是从左向右构造以某个点为结尾的线性基(否则也可以反方向构造,51nod的那道题两个方向都可以)。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 600000;
int a[maxn];
struct L_B{
int d[32],idx[32],r;
L_B(){
memset(d,0,sizeof(d));
}
void clear(){
memset(d,0,sizeof(d));
}
bool insert(int x,int id){
for(int i=30;i>=0;i--){
if(x&(1<<i)){
if(d[i]){
if(id>idx[i]){
swap(idx[i],id);
swap(d[i],x);
}
x^=d[i];
}
else{
d[i]=x;
idx[i]=id;
r++;
break;
}
}
}
return x>0;
}
int query_max(int l){
int ret=0;
for(int i=30;i>=0;i--){
if(idx[i]>=l&&(ret^d[i])>ret)
ret^=d[i];
}
return ret;
}
}lb[maxn];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
lb[0].clear();
for(int i=1;i<=n;i++){
lb[i]=lb[i-1];
lb[i].insert(a[i],i);
}
int ans=0;
while(m--){
int op;
scanf("%d",&op);
if(op==0){
int l,r;
scanf("%d%d",&l,&r);
l=(l^ans)%n+1;
r=(r^ans)%n+1;
if(l>r) swap(l,r);
ans=lb[r].query_max(l);
printf("%d\n",ans);
}
else{
int tmp;
scanf("%d",&tmp);
tmp^=ans;
n++;
lb[n]=lb[n-1];
lb[n].insert(tmp,n);
}
}
}
return 0;
}
关于线性基构造方式证明可以参考这个博客:参考博客。