2017 ICPC 西安站现场赛 A.XOR (线段树+线性基)(UVALive - 8512)

 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
#include
#include
#include
#include
#include
#include
#include
#include
#include

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<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<=(1ll<=0;i--)
            if (k&(1ll<=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<

 

你可能感兴趣的:(各种OJ题解)