[UOJ]#91. 【集训队互测2015】最大异或和 线性基

Description

我有一个数列 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an,每个 a i a_i ai 都是小于 2 m 2^m 2m 的非负整数。
现在请您实现三种操作,格式说明如下:
1   x   y   w 1\ x\ y\ w 1 x y w:对于所有 x ≤ i ≤ y x≤i≤y xiy,将 a i ai ai 修改为 a i   x o r   w a_i\ xor\ w ai xor w。其中 w w w 是一个小于 2 m 2^m 2m 的非负整数。
2   x   y   w 2\ x\ y\ w 2 x y w:对于所有 x ≤ i ≤ y x≤i≤y xiy,将 a i a_i ai 修改为 w w w。其中 w w w 是一个小于 2 m 2^m 2m 的非负整数。
3 3 3:从 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an 中选出若干个数,使得选出的数异或和最大。请输出这个最大值。

题解:

将原序列差分,bi=ai^ai-1,每次区间异或就相当于修改两个数,区间赋值就相当于删除一些数,修改两个数,修改=删除+插入,瓶颈在于怎么在线性基中删一个数,维护每个数在序列出现的时间区间[li,ri],按时间轴扫过去,在线性基加入一个数时,从高位往低位,若现在可以插入第w位,第w位无值直接插入,有值假设这个值j的区间是[lj,rj],若rj<ri就把j取出来,i插入,把取出来的数接着往下插,这样删除一个数时可以直接从线性基中删掉他,基中没有其他数可以替代他的位置

这个思路对于很多难以删除的东西都是十分适用的,要好好记住。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=2010;
const int inf=2147483647;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,m,q,R[Maxn],id[Maxn],cnt;//id[i] i位置上数的编号 
bool mark[Maxn];
struct Node{bitset<Maxn>t;int l,r;}p[Maxn<<3];
char str[Maxn];
bitset<Maxn>a[Maxn],b[Maxn],c[Maxn],w,tmp;
void insert(int o)
{
	tmp=p[o].t;
	for(int i=m-1;i>=0;i--)
	if(tmp[i])
	{
		if(R[i]<=p[o].l){c[i]=tmp;R[i]=p[o].r;return;}
		if(R[i]<p[o].r)swap(R[i],p[o].r),swap(tmp,c[i]);
		tmp^=c[i];
	}
}
bitset<Maxn>re;
void query(int tim)
{
	re.reset();
	for(int i=m-1;i>=0;i--)
	if(!re[i]&&R[i]>=tim)re^=c[i];
	for(int i=m-1;i>=0;i--)
	if(re[i])putchar('1');else putchar('0');
	putchar('\n');
}
vector<int>h[Maxn];
int main()
{
	memset(R,0,sizeof(R));
	n=read(),m=read(),q=read();a[0].reset();cnt=n;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",str);
		a[i].reset();
		for(int j=0;j<m;j++)a[i][j]=str[m-j-1]-'0';
	}
	for(int i=1;i<=n;i++)
	{
		b[i]=a[i]^a[i-1];
		id[i]=i;p[i].t=b[i];p[i].l=1,p[i].r=q;
	}
	for(int i=1;i<=q;i++)
	{
		int op=read();
		if(op==3){mark[i]=true;continue;}
		int x=read(),y=read();scanf("%s",str);
		w.reset();
		for(int j=0;j<m;j++)w[j]=str[m-j-1]-'0';
		if(op==1)
		{
			for(int j=x;j<=y;j++)a[j]^=w;
			p[id[x]].r=i;
			b[x]^=w;
			p[id[x]=++cnt].l=i,p[id[x]].r=q,p[id[x]].t=b[x];
			if(y<n)
			{
				p[id[y+1]].r=i;
				b[y+1]^=w;
				p[id[y+1]=++cnt].l=i,p[id[y+1]].r=q,p[id[y+1]].t=b[y+1];
			}
		}
		else
		{
			for(int j=x;j<=y;j++)a[j]=w;
			p[++cnt].l=i;p[cnt].r=q;p[cnt].t.reset();
			for(int j=x+1;j<=y;j++)
			{
				p[id[j]].r=i,b[j].reset();
				id[j]=cnt;
			}
			p[id[x]].r=i;
			b[x]=w^a[x-1];
			p[id[x]=++cnt].l=i,p[id[x]].r=q,p[id[x]].t=b[x];
			if(y<n)
			{
				p[id[y+1]].r=i;
				b[y+1]=w^a[y+1];
				p[id[y+1]=++cnt].l=i,p[id[y+1]].r=q,p[id[y+1]].t=b[y+1];
			}
		}
	}
	for(int i=1;i<=cnt;i++)h[p[i].l].push_back(i);
	for(int i=1;i<=q;i++)
	{
		for(int j=0;j<h[i].size();j++)insert(h[i][j]);
		if(mark[i])query(i);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值