2017 ICPC西安区域赛 A - XOR (线段树并线性基)

链接:https://nanti.jisuanke.com/t/A1607

题面:

 

Consider an array AA with n elements . Each of its element is A[i]A[i(1 \le i \le n)(1in) . Then gives two integers QQ, KK, and QQ queries follow . Each query , give you LL, RR, you can get ZZ by the following rules.

To get ZZ , at first you need to choose some elements from A[L]A[L] to A[R]A[R] ,we call them A[i_1],A[i_2]…A[i_t]A[i1],A[i2]A[it] , Then you can get number Z = KZ=K or (A[i_1]A[i1] xor A[i_2]A[i2] … xor A[i_t]A[it]) .

Please calculate the maximum ZZ for each query .

Input

Several test cases .

First line an integer T(1 \le T \le 10)(1T10) . Indicates the number of test cases.Then TT test cases follows . Each test case begins with three integer NN, QQ, K(1 \le N \le 10000,\ 1 \le Q \le 100000 , \ 0 \le K \le 100000)(1N10000, 1Q100000, 0K100000) . The next line has NN integers indicate A[1]A[1] to A[N]A[N(0 \le A[i] \le 10^8)(0A[i]108). Then QQ lines , each line two integer LL, R(1 \le L \le R \le N)(1LRN) .

Output

For each query , print the answer in a single line.

样例输入

1
5 3 0
1 2 3 4 5
1 3
2 4
3 5

样例输出

3
7
7

题目来源

ACM-ICPC 2017 Asia Xi'an

 

跟树套树差不多,线段树每个节点建个线性基,写个合并函数,对k取反,每个数对取反后的k取且,就可以转化成线性基中取与k异或最大值了

 

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int M = 1e4+10;
int a[M];
struct L_B{
    int b[33],nb[33],tot;
    void init(){
        memset(b,0,sizeof(b));
    }

    bool Insert(int x){
        for(int i = 30;i >= 0;i --){
            if(x&(1<<i)){
                if(!b[i]){
                    b[i] = x;
                    break;
                }
                x ^= b[i];
            }
        }
        return x > 0;
    }

    int Max(int x){
        int ret = x;
        for(int i = 30;i >= 0;i --)
            ret = max(ret,ret^b[i]);
        return ret;
    }

    int Min(int x){
        int ret = x;
        for(int i = 0;i <= 30;i ++)
            if(b[i]) ret ^= b[i];
        return ret;
    }

    void rebuild(){
        for(int i = 30;i >= 0;i --)
            for(int j = i-1;j >= 0;j --)
                if(b[i]&(1<<j)) b[i]^=b[j];
        for(int i = 0;i <= 30;i ++)
            if(b[i]) nb[tot++] = b[i];
    }

    int K_Min(int k){
        int res = 0;
        if(k >= (1<<tot))
            return -1;
        for(int i = 30;i >= 0;i --)
            if(k&(1<<i))
                res ^= nb[i];
        return res;
    }

    L_B merge(L_B v){
        L_B ret;
        for(int i = 0;i <= 30;i ++) ret.b[i] = b[i];
        for(int i = 0;i <= 30;i ++){
            for(int j = i;j >= 0;j --){
                if(v.b[i]&(1<<j)){
                    if(ret.b[j]) v.b[i] ^= ret.b[j];
                    else {
                        ret.b[j] = v.b[i]; break;
                    }
                }
            }
        }
        return ret;
    }
}t[M<<2];

void build(int l,int r,int rt){
    if(l == r){
        t[rt].init();
        t[rt].Insert(a[l]);
        return ;
    }
    mid;
    build(lson); build(rson);
    t[rt] = t[rt<<1].merge(t[rt<<1|1]);
}

L_B query(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return t[rt];
    }
    mid;
    if(L <= m&&m < R) return query(L,R,lson).merge(query(L,R,rson));
    if(L <= m) return query(L,R,lson);
    if(R > m) return query(L,R,rson);
}

int main()
{
    int T,n,q,k,l,r;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&q,&k);
        k = ~k;
        for(int i = 1;i <= n;i ++)
            scanf("%d",&a[i]),a[i]&=k;
        k = ~k;
        build(1,n,1);
        for(int i = 1;i <= q;i ++){
            scanf("%d%d",&l,&r);
            L_B ans = query(l,r,1,n,1);
            int an = ans.Max(k);
            printf("%d\n",an);
        }
    }
    return 0;
}

 

posted @ 2019-05-11 19:52  冥想选手  阅读(536)  评论(0编辑  收藏  举报