XOR
Consider an array A with n elements. Each of its element is A[i] (1 ≤ i ≤ n). Then gives two integers
Q, K, and Q queries follow. Each query, give you L, R, you can get Z by the following rules.
To get Z, at first you need to choose some elements from A[L] to A[R], we call them A[i1], A[i2],
. . . , A[it], Then you can get number Z = K or (A[i1], A[i2], . . . , A[it]).
Please calculate the maximum Z for each query .
Input
Several test cases.
First line an integer T (1 ≤ T ≤ 10). Indicates the number of test cases.
Then T test cases follows. Each test case begins with three integer N, Q, K (1 ≤ N ≤ 10000,1 ≤
Q ≤ 100000, 0 ≤ K ≤ 100000). The next line has N integers indicate A[1] to A[N] (0 ≤ A[i] ≤ 108).
Then Q lines, each line two integer L, R (1 ≤ L ≤ R ≤ N).
Output
For each query, print the answer in a single line.
Sample Input
1
5 3 0
1 2 3 4 5
1 3
2 4
3 5
Sample Output
3
7
7
題意:t組數據,然後輸入n,k,q,接着給出一個1個長度爲n的數組,q個詢問,對於每個詢問,詢問在下標爲[l,r]的數中,選取一部分數,使得其異或值再OR上k後最大,輸出這個最大值。
思路:根據題意,選取一部分值得到異或最大值,可以想到線性基,但是最後要OR上k,所以要消除k對其影響,我們就把每個數轉化成二進制,然後將k爲1的位置對於每個數其位置就變爲0,這樣就可以消除其k的影響了,最後在OR上k變回來,即爲正確答案。比如數a[i]=6(110) ,k = 4(100),則a[i]應該變爲(010)=2這樣來消除k的影響。由於多次區間詢問,所以用線段樹維護一下即可。
AC代碼:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
using namespace std;
#define FOU(i,x,y) for(int i=x;i<=y;i++)
#define FOD(i,x,y) for(int i=x;i>=y;i--)
#define MEM(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)
const double EXP = 1e-9;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const ll MINF = 0x3f3f3f3f3f3f3f3f;
const double DINF = 0xffffffffffff;
const int mod = 1e9+7;
const int N = 1e4+5;
//線性基
struct L_B{
ll d[63],new_d[63]; //d數組是第一次線性基,new_d是用於求Kth的線性基
int cnt; //記錄個數
L_B(){
memset(d,0,sizeof(d));
memset(new_d,0,sizeof(new_d));
cnt=0;
}
void clear(){
memset(d,0,sizeof(d));
memset(new_d,0,sizeof(new_d));
cnt=0;
}
bool ins(ll val){
for(int i=62;i>=0;i--){
if(val&(1ll<<i)){ //存在貢獻則繼續
if(!d[i]){ //線性基不存在,選入線性基中
d[i]=val;
break;
}
val^=d[i]; //否則直接改變其值
}
}
return val>0; //大於0則是成功加入線性基的向量
}
ll query_max(){
ll ans=0;
for(int i=62;i>=0;i--)
if((ans^d[i])>ans) //能讓值變大則選入
ans^=d[i];
return ans;
}
ll query_min(){
for(int i=0;i<=62;i++)
if(d[i]) //最小異或值
return d[i];
return 0;
}
//以下代碼爲求第k大異或值,其中cnt用於判斷是否可以取到0
// cnt==n(數的個數)則不可以取到0,第k小就是第k小,否則第k小是第k-1小
void rebuild()
{
for(int i=62;i>=0;i--)
for(int j=i-1;j>=0;j--)
if (d[i]&(1LL<<j))
d[i]^=d[j];
for (int i=0;i<=62;i++)
if (d[i])
new_d[cnt++]=d[i];
}
ll kthquery(int k)
{
ll ans=0;
if (k>=(1ll<<cnt))
return -1;
for (int i=62;i>=0;i--)
if (k&(1ll<<i))
ans^=new_d[i];
return ans;
}
};
//線性基合併,暴力合併
L_B merge(const L_B &n1,const L_B &n2)
{
L_B ret=n1;
for (int i=62;i>=0;i--)
if (n2.d[i])
ret.ins(n2.d[i]);
return ret;
}
ll n,q,k,pd,a[N];
L_B A;
struct node{
int lft,rht;
L_B lb;
}tree[N<<2];
void pushUp(int id){
tree[id].lb = merge(tree[id<<1].lb,tree[id<<1|1].lb);
}
void build(int id,int l,int r){
tree[id].lft=l;
tree[id].rht=r;
if(l==r){
tree[id].lb.clear();
tree[id].lb.ins((a[l]&pd));
return ;
}
int mid = (l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushUp(id);
}
void query(int id,int l,int r){
if(l==tree[id].lft&&r==tree[id].rht){
A = merge(A,tree[id].lb);
return ;
}
int mid = (tree[id].lft+tree[id].rht)>>1;
if(r<=mid){
query(id<<1,l,r);
}
else if(l>mid){
query(id<<1|1,l,r);
}
else{
query(id<<1,l,mid);
query(id<<1|1,mid+1,r);
}
}
int main()
{
std::ios::sync_with_stdio(false);
int t;
scanf("%d",&t);
while(t--){
scanf("%lld%lld%lld",&n,&q,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
pd=0;
for(int i=0;i<=62;i++){
if(k&(1ll<<i))
;
else
pd+=(1ll<<i);
}
build(1,1,n);
int l,r;
while(q--){
scanf("%d%d",&l,&r);
A.clear();
query(1,l,r);
printf("%lld\n",A.query_max()|k);
}
}
return 0;
}