cats 的集合 1

题目链接

  • 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();
}
posted @ 2024-08-25 13:59  D06  阅读(69)  评论(0)    收藏  举报
//雪花飘落效果