Duff as a Queen
题解
挺水的
对于两个线性基,如果一个线性基的任一元素能被另一个表示出来,那么这两个线性基就是等价的。显而易见
我们令,用于维护前缀的异或和。那么,我们查询的序列
就可以表示成
的样子。这样对于任一一个b操作,我们只需修改两端的b数组了。
而通过与
所构造的线性基是与原序列等价的。
之后就只需要维护a数组与b数组就可以解决修改的问题了。a数组需要维护区间修改,b数组需要维护单点修改。对于b数组线性基的维护,需要在树上合并线性基,也就是构造一个满足两个线性基的线性基。
而之后的询问与hdu3949这道板子题很像。也就是线性基大小的二次幂。
源码
#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;
}