UVALive - 8512——线段树维护线性基

【题目描述】
UVALive - 8512XOR
【题目分析】
这种区间+线性基的问题我们可以考虑用线段树维护,线性基的合并的话就直接暴力合并
找到所在区间的线性基后再查找最大的数,我看网上的博客要说消除k的影响什么的,我觉得没有什么必要,直接将初值设置为k,然后从高位向低位找,如果异或了后值会变大就异或,觉得没有什么大问题。还有就是线段树维护的时候函数的返回值最好不要设置成线性基,会RE,具体的为什么我也不清楚。这道题的RE很玄学,我把读入数据改成longlong就会RE,T和u,v里面都一个不是longlong就不会RE,我提交了20多次才敢确定的确是因为这个原因导致RE,emmm,比较玄学
【AC代码】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<climits>
#include<cstdlib>
#include<cmath>

using namespace std;

typedef long long ll;

const int MAXN=10005;
int n,m,kk;
int a[MAXN];
struct L_B
{
	ll b[65],p[65];
	int cnt,flag;
	L_B()
	{
		memset(p,0,sizeof(p));
		memset(b,0,sizeof(b));
		cnt=flag=0;
	}
	void clear()
	{
		memset(p,0,sizeof(p));
		memset(b,0,sizeof(b));
		cnt=flag=0;
	}
	inline bool insert(ll x)
	{
		for(int i=62;i>=0;--i)
			if(x&(1ll<<i))
			{
				if(b[i])
					x^=b[i];
				else
				{
					b[i]=x;
					return true;
				}
			}
		flag=1;
		return false;
	}
	ll get_max()
	{
		ll ret = 0;
		for(int i=62;i>=0;--i)
			if((ret^b[i])>ret)
				ret^=b[i];
		return ret;
	}
	ll get_max(ll initval)
	{
		ll ret = initval;
		for(int i=62;i>=0;--i)
			if((ret^b[i])>ret)
				ret^=b[i];
		return ret;
	}
	ll get_min()
	{
		if(flag)
			return 0;
		for(int i=0;i<=62;++i)
			if(b[i])
				return b[i];
		return 0;
	}
	inline void rebuild()
	{
		for(int i=1;i<=62;++i)
			if(b[i])
				for(int j=0;j<i;++j)
					if(b[i]&(1ll<<j))
						b[i]^=b[j];
		for(int i=0;i<=62;++i)
			if(b[i])
				p[cnt++]=b[i];
	}
	ll kth(ll k)
	{
		if(flag)
			--k;
		if(k==0)
			return 0;
		ll ret = 0;
		if(k>=(1ll<<cnt))
			return -1;
		for(int i=0;i<=cnt-1;++i)
			if(k&(1ll<<i))
				ret^=p[i];
		return ret;
	}
};
L_B A;
struct node
{
	L_B lis;
}tree[MAXN<<2];

L_B merge(const L_B &n1,const L_B &n2)
{
	L_B ret = n1;
	for(int i = 0;i <= 62;++i)
		if(n2.b[i])
			ret.insert(n2.b[i]);
	ret.flag = n1.flag | n1.flag;
	return ret;
}


void build(int k,int l,int r)
{
	if(l==r)
	{
		tree[k].lis.insert(a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid); build(k<<1|1,mid+1,r);
	tree[k].lis=merge(tree[k<<1].lis,tree[k<<1|1].lis);
}

void query(ll k,ll l,ll r,ll L,ll R)
{
	if(l>=L && r<=R)
	{
		A=merge(A,tree[k].lis);
		return;
	}
	int mid=(l+r)>>1;
	if(L<=mid) query(k<<1,l,mid,L,R);
	if(R>mid) query(k<<1|1,mid+1,r,L,R);
	return ;
}

int main()
{
	ll T,u,v;
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%d%d%d",&n,&m,&kk);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		
		build(1,1,n);
		
		for(int i=0;i<m;i++)
		{
			A.clear();
			scanf("%lld%lld",&u,&v);
			query(1,1,n,u,v);
			printf("%lld\n",A.get_max(kk));
		}
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值