前缀线性基 HDU6579 Operation (HDU多校)

50 篇文章 0 订阅

前缀线性基是建立在线性基得基础上的,还不会线性基请看:线性基浅谈

线性基用来处理整个区间异或的最大值、最小值等等

前缀线性基用来维护整个区间中的一段区间的最大值、最小值等等

前缀线性基的构造思路:是对于i都建立一个1~i的数组成的线性基。

比如4个数,就建1      1、2      1、2、3      1、2、3、4    这里的1 2 3 4表示第1个数,第2个数...,不是真实的值

我们把 1 叫第一个基     1、2叫第二个基      1、2、3 叫第三个基     1、2、3、4  叫第四个基

构造第i个基的时候,线从i-1个基复制过来,然后加上第i个数,如果对于基种某个位置上的数有比他更新的数就替换了(这样保证了对于某个右端点R能尽可能的用靠近R的数作为基,也就保证了所有[L,R]中的数都尽可能的参与构造这个数,比所说对于第五个基的第3个位置,如果第四个数和第二个数都能放在这个位置,就放第四个数,因为查询区间[3,5]能用3,4,5的数构造这个数,包含了4,查询区间[2,5]能用2,3,4,5的数构造这个数,也就是说对于[2,5]他无所谓用第四个数还是第二个数因为他都能用,但是[3,5]区间只能用4,所以当第四个数和第二个数都能放在第3个位置优先用第四个数)

查询的时候:如果要查询[L,R],就找到第R个基,然后记录pos[i],表示第i个位置是那个数,如果pos<l就不算是[L,R]的基

具体看代码:

Operation

Operation

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2840    Accepted Submission(s): 867


 

Problem Description

There is an integer sequence a of length n and there are two kinds of operations:
  • 0 l r: select some numbers from al...ar so that their xor sum is maximum, and print the maximum value.
  • 1 x: append x to the end of the sequence and let n=n+1.
 

 

 

Input

There are multiple test cases. The first line of input contains an integer T(T≤10), indicating the number of test cases.
For each test case: 
The first line contains two integers n,m(1≤n≤5×105,1≤m≤5×105), the number of integers initially in the sequence and the number of operations.
The second line contains n integers a1,a2,...,an(0≤ai<230), denoting the initial sequence.
Each of the next m lines contains one of the operations given above.
It's guaranteed that ∑n≤106,∑m≤106,0≤x<230.
And operations will be encrypted. You need to decode the operations as follows, where lastans denotes the answer to the last type 0 operation and is initially zero: 
For every type 0 operation, let l=(l xor lastans)mod n + 1, r=(r xor lastans)mod n + 1, and then swap(l, r) if l>r.
For every type 1 operation, let x=x xor lastans.

 

 

Output

For each type 0 operation, please output the maximum xor sum in a single line.

 

 

Sample Input

 

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

 

 

Sample Output

 

1 3

 

 

Source

2019 Multi-University Training Contest 1

 

 

Recommend

#include <bits/stdc++.h>
#define FOR(I,S,T) for(int I=(S);I<=(T);I++)
using namespace std;
const int maxn = 5e5 + 5;
int n, N;
struct Guass{
    int x[32], pos[32];//最后一个修改i这个位置得数
}a[maxn];

void Insert(int v){
    N++;
    a[N] = a[N- 1];
    int P = N;
    for (int i = 31; i >= 0; i--){
        if((v >> i) & 1){
            if (!a[N].x[i]){
                a[N].x[i] = v;
                a[N].pos[i] = P;
                break;
            }else {
                if (a[N].pos[i] < P) swap(a[N].pos[i], P), swap(a[N].x[i], v);
                v ^= a[N].x[i];
            }
        }
    }
}

int Query(int l, int r){
    int res = 0;
    for (int i = 31; i >= 0; i--){
        if (a[r].pos[i] < l) continue;
        if ((res ^ a[r].x[i]) > res) res ^= a[r].x[i];
    }
    return res;
}

int main(){
    int T;
    cin >> T;
    while (T--){
        memset(a[0].x, 0, sizeof(a[0].x));
        memset(a[0].pos, 0, sizeof(a[0].pos));
        int q;
        N = 0;
        int ans = 0;

        scanf("%d%d", &n, &q);
        for (int i = 1; i <= n; i++){
            int x;
            scanf("%d", &x);
            Insert(x);
        }
        for (int i = 1; i <= q; i++){
            int ope = 0;
            scanf("%d", &ope);
            if (ope == 0){
                int x = 0, y = 0;
                scanf("%d%d", &x, &y);
                x = (x ^ ans) % N + 1;
                y = (y ^ ans) % N + 1;
                if (x > y) swap(x, y);
                ans = Query(x, y);
               // cout << x << " " << y << endl;
                printf("%d\n", ans);
            }else{
                int x;
                scanf("%d", &x);
                x ^= ans;
                Insert(x);
            }
        }

    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值