- 0/1 Trie
- 具象化一次操作对数据结构产生的影响
- 试想,如果我们在一次修改指令中逐一更新了子树p中的所有节点,但是在之后的查询指令中却根本没有用到,那么更新p的整棵子树就是徒劳的
- 精妙的懒标记设计,详见代码注释
- (1ll<60)
- 用类实现懒标记
- 无法读取文件是因为UTF-8 BOM,另存为UTF-8就好了
- 在有操作2、3的情况下,对操作4也要采取同样的处理方法
- 否则,举个最简单的反例:用3操作清零字典树,之前的异或操作也会失效,不能作用在查询的数上
- 多测的清空
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int t[400000*31+5][2],tot,T;
const int maxn=(1ll<<31)-1;
//本题的懒标记思想好精妙,以下直接复制了题解的代码, 并尝试对其做出解释
//首先,把对第i层的修改放到根节点上下传,并用二进制数压缩表示
class LazyTag
{
public:
int o,a,x;
LazyTag()
{
o=a=x=0;
}
LazyTag(int O,int A,int X)
{
o=O;
a=A;
x=X;
}
void merge(LazyTag &m)
{
o^=o&m.a;//and操作抵消or操作
a^=a&m.o;//or操作抵消and操作
int xx=(o&m.x)|(a&m.x);
o^=xx;//异或操作抵消or操作,新增and+xor等价的or操作
o|=m.o;//合并or操作
a^=xx;//异或操作抵消and操作,新增or+xor等价的and操作
a|=m.a;//合并and操作
x^=((x&m.a)|(x&m.o))^m.x^xx;//更新xor操作
}
void clean()
{
o=a=x=0;
}
}f[400000*31+5];
void spread(int p,int i);
int merge(int p,int q,int i)
{
if(!p)
{
return q;
}
if(!q)
{
return p;
}
if(i==-1)
{
return p;
}
spread(p,i);
spread(q,i);
t[p][0]=merge(t[p][0],t[q][0],i-1);
t[p][1]=merge(t[p][1],t[q][1],i-1);
t[q][0]=t[q][1]=0;
return p;
}
void insert(int x)
{
int p=0;
for(int i=30;i>=0;i--)
{
spread(p,i);
int y=((x>>i)&1);
if(!t[p][y])
{
t[p][y]=++tot;
f[tot].clean();
t[tot][0]=t[tot][1]=0;
}
p=t[p][y];
}
}
int ask(int x)
{
int p=0,ans=0;
for(int i=30;i>=0;i--)
{
spread(p,i);
int y=(((x>>i)&1)^1);
if(t[p][y])
{
p=t[p][y];
ans+=(1<<i);
}
else
{
p=t[p][y^1];
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
tot=0;
f[0].clean();
t[0][0]=t[0][1]=0;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
insert(x);
}
for(int i=1;i<=m;i++)
{
int opt,x;
cin>>opt>>x;
LazyTag tmp1(x,0,0);
LazyTag tmp2(0,x^maxn,0);
LazyTag tmp3(0,0,x);
switch(opt)
{
case 1:
insert(x);
break;
case 2:
f[0].merge(tmp1);
break;
case 3:
f[0].merge(tmp2);
break;
case 4:
f[0].merge(tmp3);
break;
case 5:
cout<<ask(x)<<endl;
break;
}
}
}
return 0;
}
void spread(int p,int i)
{
int o=(f[p].o>>i)&1;
int a=(f[p].a>>i)&1;
int x=(f[p].x>>i)&1;
if(o)
{
t[p][1]=merge(t[p][1],t[p][0],i-1);
t[p][0]=0;
}
if(a)
{
t[p][0]=merge(t[p][0],t[p][1],i-1);
t[p][1]=0;
}
if(x)
{
swap(t[p][0],t[p][1]);
}
if(t[p][0])
{
f[t[p][0]].merge(f[p]);
}
if(t[p][1])
{
f[t[p][1]].merge(f[p]);
}
f[p].clean();
}