hdu6579 2019hdu多校第一场1002

这题是cf 1100F原题,场上一堆人做出来了,然后我线段树线性基时间也过不去,空间也过不去

看了题解后发现是个很容易的套路

我们对1...i的数组维护一个b[i]的前缀和线性基,但是线性基中的数字,我们每一位都要记录一个pos[k]表示p[k]是由第pos[k]个数字填进去的,在插入的时候,我们让k从高往低优先插入当前位置大的数字,就算当前p[i]已经有数字了,如果pos[k]<当前插入数字的id,那么我们把p[i]和插入的x交换,因为要让更靠右的数字尽可能插入在更高位。

这样我们求l,r中线性基最大值,就从去b[r]中,从高到底,如果当前pos[k]>=l,那么说明p[i]是由l-r中的数字异或出来的,那么我们就可以考虑是否对答案res进行异或p[k]。

#include<bits/stdc++.h>
#define maxl 1000010

using namespace std;

int n,m,ans;
int a[maxl];
struct LB
{
	int p[31],pos[31];
	inline void init()
	{
		for(int i=0;i<=30;i++)
			p[i]=0,pos[i]=0;
	}
	inline void insert(int x,int id)
	{
		for(int i=30;i>=0;i--)
		if(x&(1<<i))
		{
			if(!p[i])
			{
				p[i]=x;
				pos[i]=id;
				return;
			}
			if(id>pos[i])
			{
				swap(x,p[i]);
				swap(id,pos[i]);
			}
			x^=p[i];
		}
	}
	inline int getmax(int l)
	{
		int res=0;
		for(int i=30;i>=0;i--)
		if(pos[i]>=l && (res^p[i])>res)
			res^=p[i];
		return res;
	}
}b[maxl];

inline void prework()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		b[i]=b[i-1];
		b[i].insert(a[i],i);
	}
}

inline void mainwork()
{
	int l,r,op,x;ans=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&op);
		if(op==0)
		{
			scanf("%d%d",&l,&r);
			l=(l^ans)%n+1;
			r=(r^ans)%n+1;
			if(l>r) swap(l,r);
			ans=b[r].getmax(l);
			printf("%d\n",ans);
		}
		else
		{
			scanf("%d",&x);
			x^=ans;
			a[++n]=x;
			b[n]=b[n-1];
			b[n].insert(a[n],n);
		}
	}
}

inline void print()
{
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值