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;
}
關於線性基構造方式證明可以參考這個博客:參考博客。