2019.01.25【LOJ6144】2017 山东三轮集训 Day6」C(可持久化01Trie)

传送门


解析:

实际上这道题的做法非常直白。。。以及暴力。。。

思路:

考虑如果没有 a n d and and o r or or两个操作,只有 x o r xor xor的话,显然我们只需要维护一个 x o r t a g xortag xortag就可以轻松解决这个问题。

那么现在有了 a n d and and o r or or,这个问题就显得有点麻烦了。

考虑 a n d and and o r or or总是在不断地将不同的位变得相同。。。

所以我们只需要维护当前 A A A数列中所有数有哪些位置是已经全部相同了的。

然后每次有 a n d and and o r or or把本来不同的地方变得相同的时候,我们暴力重构 01 T r i e 01Trie 01Trie

显然这样的重构不会超过 30 30 30次,直接做就好了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline char getalpha(){
		re char c;
		while(!isalpha(c=gc()));return c;
	}
} 
using namespace IO;

cs int N=50004,B=40;

int n,m,_1to=0x7fffffff,_0to=0,xortag;

int rt[N];
int son[N*(B+1)][2],siz[N*(B+1)],tot;

bool same[B+1];
int opt[B+1];

inline void insert(int pre,int now,int val){
	for(int re i=30;~i;--i){
		bool f=same[i]?0:((val>>i)&1);
		siz[now]=siz[pre]+1;
		son[now][!f]=son[pre][!f];
		now=son[now][f]=++tot;
		pre=son[pre][f];
	}
	siz[now]=siz[pre]+1;
}

int a[N];
inline void build(){
	memset(siz,0,sizeof(int)*(tot+1));
	memset(son,0,sizeof(int)*(tot+1)*2);
	rt[0]=tot=1;
	insert(0,rt[0],0);
	for(int re i=1;i<=n;++i){
		rt[i]=++tot;
		insert(rt[i-1],rt[i],a[i]);
	}
}

inline int query(int lt,int rt,int k){
	int ans=0;
	for(int re i=30;~i;--i){
		if(same[i])ans|=opt[i]<<i,lt=son[lt][0],rt=son[rt][0];
		else {
			bool f=xortag&(1<<i);
			int sze=siz[son[rt][f]]-siz[son[lt][f]];
			if(sze>=k){
				rt=son[rt][f];
				lt=son[lt][f];
			}
			else {
				k-=sze;
				ans|=1<<i;
				rt=son[rt][!f];
				lt=son[lt][!f];
			}
		}
	}
	return ans;
}

signed main(){
	n=getint(),m=getint();
	for(int re i=1;i<=n;++i){
		a[i]=getint();
		_1to&=a[i];
		_0to|=a[i];
	}
	for(int re i=0;i<=30;++i)same[i]=(_1to>>i)==(_0to>>i);
	build();
	while(m--){
		char op=getalpha();
		if(op=='A')op=getalpha();
		switch(op){
			case 'X':{
				int x=getint();
				xortag^=x;
				for(int re i=0;i<=30;++i)if(same[i]&&(x&(1<<i)))opt[i]^=1;
				break;
			}
			case 'n':{
				int a=getint();
				bool flag=0;
				for(int re i=0;i<=30;++i)
				if(!(a&(1<<i))){
					if(same[i])opt[i]=0;
					else {
						flag=true;
						same[i]=1;
						opt[i]=0;
					}
				}
				if(flag)build();
				break;
			}
			case 'O':{
				int o=getint();
				bool flag=0;
				for(int re i=0;i<=30;++i)
				if(o&(1<<i)){
					if(same[i])opt[i]=1;
					else {
						flag=true;
						same[i]=1;
						opt[i]=1;
					}
				}
				if(flag)build();
				break;
			}
			case 's':{
				int l=getint(),r=getint(),k=getint();
				cout<<query(rt[l-1],rt[r],k)<<"\n";
				break;
			}
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值