【题目】
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1422 Accepted Submission(s): 445
Problem Description
There is an integer sequence of length and there are two kinds of operations:
- 0 l r: select some numbers from so that their xor sum is maximum, and print the maximum value.
- 1 x: append to the end of the sequence and let .
Input
There are multiple test cases. The first line of input contains an integer , indicating the number of test cases.
For each test case:
The first line contains two integers , the number of integers initially in the sequence and the number of operations.
The second line contains integers , denoting the initial sequence.
Each of the next lines contains one of the operations given above.
It's guaranteed that .
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.
【题意】
给n个数,m次操作,每次操作有0和1,1代表着往序列最后一个插数,0代表查询l,r区间异或的最大值。
【题解】
刚开始想着线段树维护区间线性基,后来计算时间复杂度是超时的。。。但是我还尝试性的打了代码,T了两发。。。
官方题解:官方题解:贪心地维护序列的前缀线性基 (上三角形态),对于每个线性基,将出现位置靠右的数字尽可能地放在高位,也就是说在插入新数字的时候,要同时记录对应位置上数字的出现位置,并且在找到可以插入的位置的时候,如果新数字比位置上原来的数字更靠右,就将该位置上原来的数字向低位推。在求最大值的时候,从高位向低位遍历,如果该位上的数字出现在询问中区间左端点的右侧且可以使答案变大,就异或到答案里。对于线性基的每一位,与它异或过的线性基更高位置上的数字肯定都出现在它右侧 (否则它就会被插入在那个位置了),因此做法的正确性显然。
【AC代码】
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,_;
int x;
struct node
{
int m;
int xian[31];
int pos[31];
void insert(int x,int id){
for(int j=30;j>=0;j--) {
if((x>>j&1)==0) continue;
if(!xian[j])
{
xian[j]=x;
pos[j]=id;
m++;
}
if(pos[j]<id)
{
swap(x,xian[j]);
swap(id,pos[j]);
}
x^=xian[j];
}
}
void clear(){
for(int i=0;i<=30;++i) xian[i]=0;
m=0;
}
}sum[N];
void init()
{
for(int i=1;i<=n;++i) sum[i].clear();
}
int main()
{
scanf("%d",&_);
while(_--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",&x);
sum[i]=sum[i-1];
sum[i].insert(x,i);
}
int lastans=0;
while(m--)
{
int ty;
scanf("%d",&ty);
if(ty)
{
scanf("%d",&x);
++n;
x^=lastans;
sum[n]=sum[n-1];
sum[n].insert(x,n);
}
else{
int l,r;
scanf("%d%d",&l,&r);
l=(l^lastans)%n+1;
r=(r^lastans)%n+1;
if(l>r) swap(l,r);
lastans=0;
for(int i=30;i>=0;i--)
{
if(sum[r].pos[i]>=l&&(lastans^sum[r].xian[i])>lastans)
lastans^=sum[r].xian[i];
}
printf("%d\n",lastans);
}
}
init();
}
return 0;
}