Problem A: 游戏
题解&反思
模型转化挺简单的,但是转化成“查询区间内是否有若干个数组成的集合xor和为0”问题的时候,突然发现不会做……最后只打了20暴力真是凉凉。
其实线性基这个东西我应该见过好多次,然而每次都因为某些奇怪的原因没有学……今天终于填了这个坑啊。
参考:https://www.cnblogs.com/ljh2000-jump/p/5869991.html
这道题就是用线段树维护线性基。首先,ai的的范围是2^30,所以当查询区间大于30时,线性基一定小于区间数的个数,也就是一定能凑出来0,直接回答即可;否则,枚举l到r,插进线性基里,如果某次插入失败则说明能凑出0,否则puts("No");
至于线段树上的标记维护比较神奇,我已开始想的是维护&|^三个标记,结果不会写,可以维护两个标价mn和mx,互为二进制反数……好吧我现在也不知道这是维护了个啥,总之先背下来就好了= =
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=500005,sz=32768,inf=(1<<30)-1;
int n,q,a[N],b[N],v[35];
struct qwe
{
int l,r,mn,mx;
}t[N<<2];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>‘9‘||p<‘0‘)
{
if(p==‘-‘)
f=-1;
p=getchar();
}
while(p>=‘0‘&&p<=‘9‘)
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
int hig(int x)
{
return x>sz?b[x>>15]+15:b[x];
}
inline void hb(qwe &now,qwe x)
{
int p=now.mn,q=now.mx;
now.mn=(p&x.mx)|((inf^p)&x.mn);
now.mx=(q&x.mx)|((inf^q)&x.mn);
}
inline void pd(int k)
{
hb(t[k<<1],t[k]);
hb(t[k<<1|1],t[k]);
t[k].mn=0,t[k].mx=inf;
}
void build(int ro,int l,int r)
{
t[ro].l=l,t[ro].r=r;
t[ro].mx=inf;
if(l==r)
return;
int mid=(l+r)>>1;
build(ro<<1,l,mid);
build(ro<<1|1,mid+1,r);
}
void update(int ro,int l,int r,int o,int x)
{
if(t[ro].l==l&&t[ro].r==r)
{
if(o==1)
t[ro].mn&=x,t[ro].mx&=x;
else if(o==2)
t[ro].mn|=x,t[ro].mx|=x;
else if(o==3)
t[ro].mn^=x,t[ro].mx^=x;
return;
}
pd(ro);
int mid=(t[ro].l+t[ro].r)>>1;
if(r<=mid)
update(ro<<1,l,r,o,x);
else if(l>mid)
update(ro<<1|1,l,r,o,x);
else
{
update(ro<<1,l,mid,o,x);
update(ro<<1|1,mid+1,r,o,x);
}
}
qwe ques(int ro,int w)
{
if(t[ro].l==t[ro].r)
return t[ro];
pd(ro);
int mid=(t[ro].l+t[ro].r)>>1;
if(w<=mid)
return ques(ro<<1,w);
else
return ques(ro<<1|1,w);
}
int wen(int p)
{
qwe now=ques(1,p);
int q=a[p];
return (q&now.mx)|((inf^q)&now.mn);
}
bool add(int x)
{
int i;
for(i=hig(x);i>=0;i=hig(x))
{
if(v[i]==0)
{
v[i]=x;
break;
}
x^=v[i];
}
return i>=0;
}
int main()
{
b[0]=-1;
for(int i=1;i<=sz;i++)
b[i]=b[i>>1]+1;
n=read();
build(1,1,n);
for(int i=1;i<=n;i++)
a[i]=read();
q=read();
while(q--)
{
int o=read(),l=read(),r=read();
if(o)
{
int x=read();
update(1,l,r,o,x);
}
else
{
if(r-l+1>30)
{
puts("Yes");
continue;
}
bool f=1;
memset(v,0,sizeof(v));
for(int j=l;j<=r;j++)
if(!add(wen(j)))
{
f=0;
break;
}
if(f)
puts("No");
else
puts("Yes");
}
}
return 0;
}