- 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();
}