[CF587E]Duff as a Queen

Duff as a Queen

题解

挺水的

对于两个线性基,如果一个线性基的任一元素能被另一个表示出来,那么这两个线性基就是等价的。显而易见

我们令b_{i}= a_{i} \oplus a_{i-1},用于维护前缀的异或和。那么,我们查询的序列c_{l} , \, c_{l+1} ,\, ... \, , \,c_{r}就可以表示成a_{l} , \, a_{l}\oplus b_{l+1} , \, a_{l}\oplus b_{l+1}\oplus b_{l+2} , \, ...的样子。这样对于任一一个b操作,我们只需修改两端的b数组了。

而通过a_{l}b_{l+1}\, , \, ... \, ,b_{r}所构造的线性基是与原序列等价的。

之后就只需要维护a数组与b数组就可以解决修改的问题了。a数组需要维护区间修改,b数组需要维护单点修改。对于b数组线性基的维护,需要在树上合并线性基,也就是构造一个满足两个线性基的线性基。

而之后的询问与hdu3949这道板子题很像。也就是线性基大小的二次幂2^{\left | b \right |}

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define MAXN 200010
typedef long long LL;
const int MAXM=31;
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
struct LinearBase{
	int d[35];
	void clear(){memset(d,0,sizeof(d));}
	void insert(int x){
		for(int i=MAXM;~i;i--)
			if(x>>i&1){
				if(d[i])x^=d[i];
				else{d[i]=x;break;}
			}
	}
	void merge(LinearBase rhs){
		for(int i=MAXM;i>=0;i--)
			if(rhs.d[i])insert(rhs.d[i]);
	}
	int query(){
		int cnt=0;
		for(int i=MAXM;i>=0;i--)if(d[i])cnt++;
		return (1<<cnt);
	}
}A;
int a[MAXN],b[MAXN],n,q;
#define lson rt<<1
#define rson rt<<1|1
struct segmentree_section{
	int sum[MAXN<<2],lzy[MAXN<<2];
	void push_down(int rt){
		if(!lzy[rt])return ;
		lzy[lson]^=lzy[rt];lzy[rson]^=lzy[rt];
		sum[lson]^=lzy[rt];sum[rson]^=lzy[rt];
		lzy[rt]=0;
	}
	void build(int rt,int l,int r){
		if(l==r)return (void)(sum[rt]=a[l]);int mid=l+r>>1;
		build(lson,l,mid);build(rson,mid+1,r);
	}
	void updata(int rt,int l,int r,int al,int ar,int aw){
		if(al<=l&&r<=ar)return (void)(lzy[rt]^=aw,sum[rt]^=aw);
		int mid=l+r>>1;push_down(rt);
		if(al<=mid)updata(lson,l,mid,al,ar,aw);
		if(ar>mid)updata(rson,mid+1,r,al,ar,aw);
	}
	int query(int rt,int l,int r,int ai){
		//printf("%d %d %d:%d\n",rt,l,r,sum[rt]);
		if(l==r)return sum[rt];
		int mid=l+r>>1;push_down(rt);
		if(ai<=mid)return query(lson,l,mid,ai);
		return query(rson,mid+1,r,ai);
	}
}tree1;
struct segmentree_point{
	LinearBase a[MAXN<<2];
	void push_up(int rt){
		a[rt].clear();
		a[rt].merge(a[lson]);
		a[rt].merge(a[rson]);
	}
	void build(int rt,int l,int r){
		if(l==r)return (void)(a[rt].insert(b[l]));
		int mid=l+r>>1;build(lson,l,mid);
		build(rson,mid+1,r);push_up(rt);
	}
	void updata(int rt,int l,int r,int ai,int aw){
		if(l==r)return(void)(a[rt].clear(),a[rt].insert(aw));
		int mid=l+r>>1;
		if(ai<=mid)updata(lson,l,mid,ai,aw);
		else updata(rson,mid+1,r,ai,aw);
		push_up(rt);
	}
	LinearBase query(int rt,int l,int r,int al,int ar){
		if(al<=l&&r<=ar)return a[rt];
		LinearBase res;res.clear();int mid=l+r>>1;
		if(al<=mid)res.merge(query(lson,l,mid,al,ar));
		if(ar>mid)res.merge(query(rson,mid+1,r,al,ar));
		return res;
	}
}tree2;
signed main(){
	read(n);read(q);
	for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i]^a[i-1];
	tree1.build(1,1,n);tree2.build(1,1,n);
	for(int i=1;i<=q;i++){
		int opt,l,r;read(opt);read(l);read(r);
		if(opt==1){
			int w;read(w);
			tree1.updata(1,1,n,l,r,w);
			if(r!=n)tree2.updata(1,1,n,r+1,b[r+1]^=w);
			tree2.updata(1,1,n,l,b[l]^=w);
		}
		else{
			A.clear();A.insert(tree1.query(1,1,n,l));
			if(l!=r)A.merge(tree2.query(1,1,n,l+1,r));
			printf("%d\n",A.query());
		}
	}
	return 0;
}

谢谢!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值