hdu6594(线性基)

题目

进行两种操作,第一种为求区间【L,R】异或最大值,第二种为添加一个数到数列队尾


题解

这两天一直在做线性基的题,原来极为头疼的普通异或问题似乎显得不是那么的难了,但区间异或最大值却仍然对我来说有点难度。

数据结构仍然是线性基(就是线性代数的极大线性无关组,本质非常像),求所有的元素的异或最大值是线性基的模板题,不多解释,首先将问题化简为求【1,R】的区间(前缀)的最大异或,很简单,就是每次添加一个数后都进行一次LB.Max操作就行,然后把这个前缀最大值存起来,现在的问题就变成如何消除【1,L-1】的影响。

在建立线性基时用pos数组记录原数的位置,并且采取贪心的思想,以前插入操作时只要这个位置不是0就跳过直到找到空的位置为止,但现在我们只要找到位置就插入,并且把这个位置原先的值异或后取出,继续向下进行插入操作。这样,最大值值操作时,如果这个i的原先的位置在L的前面,就说明后面的数一定不能线性组合出这个基,所以跳过,只要全部跳过位置在L前面的基,就消除了【1,L-1】的影响

代码

常数太大了,哭了,压时间线AC的,我也不知道自己在写些什么

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+7;
struct  Linear_Basis{
    ll b[63],nb[63];
	int pos[63],tot; //b为线性基  nb用来求第K小异或值 tot为nb元素个数
    ll n1[maxn][32],n2[maxn][32];
    void Init(){    //初始化
        tot=0;
        memset(b,0,sizeof(b));
    }
    void Ins(ll  x,int x1){ //插入
    	int R=x1;
        for(int i=31;i>=0;i--){
            if(x&(1ll<<i)){ //判断x的第i位是否为0 
                if(!b[i]){ //判断线性基b[i]是否为空 
                    b[i]=x;
                    pos[i]=x1;
                    break;
                }
                else{
                	if(pos[i]<x1){
                		swap(b[i],x);
                		swap(pos[i],x1);
					}
				}
                x^=b[i];
            }
        }
        for(int i=31;i>=0;i--){
        	n1[R][i]=b[i];
        	n2[R][i]=pos[i];
		}
        return ;
    }
    ll Max(int L,int R){   //求最大值
        ll res=0;
        for(int i=31;i>=0;i--){
        	if(n2[R][i]>=L)
            res=max(res,res^n1[R][i]);
        }
        return res;
    }
}LB;

int main(){
	ll m1,m2,m3;
	int T,N,N1,l,r;
	cin>>T;
	while(T--){
		scanf("%d%d",&N,&N1);
		LB.Init();
		int N2=0,last=0;
		for(int i=1;i<=N;i++){
			scanf("%d",&m1);
			LB.Ins(m1,++N2);
		}
		for(int i=1;i<=N1;i++){
			scanf("%d",&m1);
			if(m1==1){
				scanf("%d",&m1);
				m1 = m1 ^ last;
				LB.Ins(m1,++N2);
			}
			else{
				scanf("%d%d",&l,&r);
				l = (l ^ last) % N2 + 1;
                r = (r ^ last) % N2 + 1;
                if(l > r) swap(l, r);
                last = LB.Max(l, r);
				cout<<last<<endl;
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值