HDU 多校第一场

B.Operation

http://acm.hdu.edu.cn/showproblem.php?pid=6579

题意:

给你一个序列,两种操作,第一种是求处区间 [ l , r ] [l,r] [l,r]的异或最大值,第二种是在序列后面加上一个值 x x x

思路:

首先肯定是线性基来做,但是如果用数据结构来优化的话,是必T的,
题解说的是按照贪心的做法来做,
线性基会用到一个大小为32的数组来记录一个x,但是贪心的做法是
线性基不仅会用到x,还会用到x的位置,并且尽量要把x的位置的值取到最大,
我们用b[i][j]来代表[1,i]这个区间里面的线性基,pos[i][j]来代表这个线性基的位置,这个位置是小于i的第一个
j位为1的数字,
比如在[1,i-1]这个序列中插入一个新的值,那么对于这个值的二进制形式从高到低遍历,如果为1那么就和原来的pos[i-1][j]比较大小,如果pos[i][j] 为什么可以这样,证明一下正确性:

线性基性质:

一个线性基,对于每一个 i , a i i,a_i i,ai,有两种可能
1. a i = 0 a_i=0 ai=0并且 只有满足 j > i j>i j>i a j a_j aj(即,位于 a i a_i ai后面所有的 a j a_j aj)的第 i i i个二进制可能为1
2. a 1 ! = 0 a_1!=0 a1!=0并且,整个a数组只有 a i a_i ai的第 i i i个二进制位1;
a i a_i ai更高的二进制位( > i >i >i的二进制位)一定为0;
a i a_i ai更低的二进制位( < i <i <i的二进制位)可能为1;
所以当我们有两个数字的第 i i i为都为1,那么贪心的原则使得我们选择位置更大的那个,位置小的那么可以取下面找比它更小的线性基

当我们要求求出 [ l , r ] [l,r] [l,r]的异或最大值是,我们从大到小遍历线性基,选择那些位置 > l >l >l并且使得ans a i a_i ai的线性基

AC代码:

#include
using namespace std;

#define ll long long
const int maxn = 1e6 + 7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> pis;

struct LB{
    int b[maxn][32], pos[maxn][32];

    void Init() {
        memset(b, 0, sizeof(b));
        memset(pos, 0, sizeof(pos));
    }  

    void Ins(int x, int w) {
        int k = w;
        for (int i = 30; i >= 0; i --) {
            b[w][i] = b[w-1][i];
            pos[w][i] = pos[w-1][i];
        }
        for (int i = 30; i >= 0; i --) {
            if(x >> i) {
                if(!b[w][i]) {
                    b[w][i] = x;
                    pos[w][i] = k;
                    return ;
                }else if(k > pos[w][i]) {
                    swap(x, b[w][i]);
                    swap(pos[w][i], k);
                }
                x ^= b[w][i];
            }
        }
    }

    int getMax(int l, int r) {
        int res = 0;
        for (int i = 30; i >= 0; i --) 
            if(pos[r][i] >= l && (res ^ b[r][i]) > res) 
                res = res ^ b[r][i];
        return res;
    }

}lb;

int main() { 
    int T;
    scanf("%d", &T);
    while(T --) {
        int n, m;
        scanf("%d %d", &n, &m);
        lb.Init();
        for (int i = 1, x; i <= n; i ++) {
            scanf("%d", &x);
            lb.Ins(x, i);
        }
        int pre = 0;
        while(m --) {
            int op;
            scanf("%d", &op);
            if(op) {
               int x;
               scanf("%d", &x);
               lb.Ins(x^pre, ++n); 
            }else {
                int l, r;
                scanf("%d %d", &l, &r);
                l = (l ^ pre) % n + 1;
                r = (r ^ pre) % n + 1;
                if(l > r) swap(l, r);
                pre = lb.getMax(l, r);
                printf("%d\n", pre);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(题解,线性基,多校)