Operation(HDU-6579)

Problem Description

There is an integer sequence aa of length nn 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 nn integers a1,a2,...,an(0≤ai<230), denoting the initial sequence. 
Each of the next mm 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

题意:t 组数据,每组给出一个长度为 n 的序列和 m 组查询,每组查询分为 2 种操作,1 x 代表将数 x 追加到序列中,0 l r 代表查询区间 [l,r] 中的最大异或和,每次给出的查询要求异或上一次的结果,强制在线

思路:

根据查询最大异或和可以想到利用线性基来做,但线性基是用来查询整个序列的最大异或和,本题仅涉及到求区间 [l,r] 的最大异或和,就需要用前缀线性基来做。

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<unordered_map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-10;
const int MOD = 1E9+7;
const int N = 500000+5;
const int dx[] = {-1,1,0,0,1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;

struct PrefixLinearBasis{
    int d[N][32];//前缀线性基
    int pos[N][32];//最后一个修改i这个位置的数
    int num;
    PrefixLinearBasis(){
        memset(d,0,sizeof(d));
        memset(pos,0,sizeof(pos));
        num=0;
    }
    void add(int x){//向线性基中添加x
        num++;
        for(int i=0; i<32; i++){//复制前num-1个线性基
            d[num][i]=d[num-1][i];
            pos[num][i]=pos[num-1][i];
        }

        int P=num;
        for(int i=31; i>=0; i--){
            if((x>>i)&1){
                if(d[num][i]){//插入失败
                    if(pos[num][i]<P){//交换位置
                        swap(pos[num][i], P);
                        swap(d[num][i],x);
                    }
                    x^=d[num][i];//异或
                }
                else{//插入成功
                    d[num][i]=x;
                    pos[num][i]=P;
                    break;
                }
            }
        }
    }
    int queryMax(int l,int r){//查询[l,r]中的最大值
        int res=0;
        for (int i=31; i>=0; i--){
            if(pos[r][i]<l) 
                continue;
            if ((res^d[r][i])>res) 
                res^=d[r][i];
        }
        return res;
    }
    int queryMin(int l,int r) {//查询[l,r]中的最小值
        for(int i=0; i<=60; i++){
            if(pos[r][i]<l)
                continue;
            if(d[r][i])
                return d[r][i];
        }
        return 0;
    }
}PLB;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        memset(PLB.d[0], 0, sizeof(PLB.d[0]));
        memset(PLB.pos[0], 0, sizeof(PLB.pos[0]));
        PLB.num=0;
 
        int n,m;
        scanf("%d%d",&n,&m);
        for (int i=1; i<=n; i++){
            int x;
            scanf("%d",&x);
            PLB.add(x);
        }

        int ans=0;
        for(int i=1; i<=m; i++){
            int op=0;
            scanf("%d",&op);
            if (op==0){
                int x = 0, y = 0;
                scanf("%d%d", &x, &y);
                x = (x ^ ans) % PLB.num + 1;
                y = (y ^ ans) % PLB.num + 1;
                if (x > y) 
                    swap(x, y);
                ans = PLB.queryMax(x, y);
                printf("%d\n", ans);
            }
            else if(op==1){
                int x;
                scanf("%d",&x);
                x^=ans;
                PLB.add(x);
            }
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值