HDU 6579 Operation (预处理线性基+在线查询)

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=6579

题意:给出一个数组,有两种操作,一种是在数组后面添一个数,一个数区间查询异或最大值。

此题原题CF1100F
不同的是CF那题没有添加操作,也没有强制在线而已.

思路:由于这个题区间查询用线段树的话时间复杂度不正确,所以要对线性基多做一点处理。

定义 p o s [ ] pos[] pos[]数组表示在线性基中第j位为1的数字在原数组的下标。
那么我们对 n n n个数的每个前缀搞个线性基,同时记录线性基的 p o s pos pos
那么假如查询区间 [ l , r ] [l,r] [l,r]的区间异或最大值,我们直接取出区间 [ 1 , r ] [1,r] [1,r]对应的线性基,然后查询这个线性基可以组成的最大值,不过要加一个判断条件,也就是如果线性基的第 i i i位是 1 1 1,那么如果 p o s [ i ] &lt; l pos[i]&lt;l pos[i]<l,答案是不会取这个值的,因为 p o s [ i ] &lt; l pos[i]&lt;l pos[i]<l就说明了在 [ 1 , r ] [1,r] [1,r]区间上,第 i i i位是 1 1 1的那个数出现在 l l l之前,所以当你查询 [ l , r ] [l,r] [l,r]的时候,是没有这个数字的。

这个题目要改变一下 i n s e r t insert insert函数的写法,把 p o s pos pos写进去。

#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
//typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
const int MAXL = 31;
const int M = 5e5 + 5;
int a[maxn][MAXL + 1];//前缀线性基
int pos[M][MAXL + 1];//记录第i位是1是哪个元素
void Insert(int id, int t, int p) {//下面写法的改变
    for (int j = MAXL; j >= 0; j--) {
        if (!(t & (1 << j))) continue;
        if (!a[j]) {
            a[id][j] = t;
            pos[id][j] = p;
            break;
        }
        if (pos[id][j] < p) {
            swap(pos[id][j], p);
            swap(a[id][j], t);
        }
        t ^= a[id][j];
    }
}
int x;
int l, r;
int T, n, m;
int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &x);
            for (int j = MAXL; j >= 0; j--) {
                pos[i][j] = pos[i - 1][j];
                a[i][j] = a[i - 1][j];
            }
            Insert(i, x, i);
        }
        int lastans = 0;
        while (m--) {
            int op;
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d", &x);
                x ^= lastans;
                n++;
                for (int j = MAXL; j >= 0; j--) {
                    pos[n][j] = pos[n - 1][j];
                    a[n][j] = a[n - 1][j];
                }
                Insert(n, x, n);
            } else {

                scanf("%d%d", &l, &r);
                l = (l ^ lastans) % n + 1;
                r = (r ^ lastans) % n + 1;
                if (l > r) {
                    swap(l, r);
                }
                int num = 0;
                for (int j = MAXL; j >= 0; j--) {
                    if (pos[r][j] < l) continue;
                    if ((num ^ a[r][j]) > num) num ^= a[r][j];
                }
                printf("%d\n", num);
                lastans = num;
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值