「2017 山东三轮集训 Day6」C(0/1 Trie)

传送门

如果没有与和或的话可以用可持久化 0 / 1   t r i e 0/1 \ trie 和 异或 t a g tag 解决这个问题
考虑与和或操作
与1和或0是没有意义的,与 0 和或 1 的意义就在于把某一位全部变成 0 或 1
而某一位全部一样过后我们就可以直接记录这一位的状态
于是修改后当某一位由不一样变成完全一样的时候,我们就暴力重构 t r i e trie 树,显然只会重构 l o g log
区间 k k 大和主席树一样,在 0 / 1   t r i e 0/1\ trie 上二分就可以了
复杂度 O ( n l o g ( A i ) 2 ) O(nlog(A_i)^2)
不对劲过后暴力重构的方法比较巧妙

#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
cs int N = 5e4 + 50, M = 32;
int n, m, a[N];
int same[M], tag[M], Xor;
namespace T{
	cs int N = ::N * 32;
	int nd, rt[N], ch[N][2], sz[N];
	void clear(){
		memset(sz,0,sizeof(int)*(nd+1));
		memset(ch,0,sizeof(int)*(nd+1)*2);
		nd=rt[0]=0;
	}
	void ins(int las, int &x, int v, int i){
		x=++nd; sz[x] = sz[las]+1; if(i<0) return;
		int c=same[i]?0:((v>>i)&1); ch[x][c^1]=ch[las][c^1];
		ins(ch[las][c],ch[x][c],v,i-1);
	}
	int query(int a, int b, int k, int i){
		if(i<0) return 0;
		if(same[i]) return query(ch[a][0],ch[b][0],k,i-1)+(tag[i]<<i);
		else{
			int c=Xor>>i&1;
			int sm=sz[ch[b][c]]-sz[ch[a][c]];
			if(k<=sm) return query(ch[a][c],ch[b][c],k,i-1);
			else return query(ch[a][c^1],ch[b][c^1],k-sm,i-1)+(1<<i);
		} 
	}
	void build(){
		clear();
		for(int i=1; i<=n; i++)
		ins(rt[i-1],rt[i],a[i],30);
	}
}
int main(){
	n = read(), m = read();
	unsigned int And=-1, Or=0; 
	for(int i=1; i<=n; i++) a[i]=read(), And=And&a[i], Or=Or|a[i];
	for(int i=0; i<=30; i++) same[i]=((And>>i)==(Or>>i));
	T::build();
	while(m--){
		char op[5]; scanf("%s", op);
		if(op[1]=='o'){
			int x = read(); Xor ^= x;
			for(int i=0; i<=30; i++) if(same[i]&&(x>>i&1)) tag[i]^=1;
		}
		if(op[1]=='n'){
			int x = read(); 
			bool FLAG = false;
			for(int i=0; i<=30; i++)
			if(!(x&(1<<i))){
				if(same[i]) tag[i] = 0;
				else{ FLAG=true; same[i]=1; tag[i]=0; }
			} if(FLAG) T::build();
		}
		if(op[1]=='r'){
			int x = read();
			bool FLAG = false;
			for(int i=0; i<=30; i++)
			if(x&(1<<i)){
				if(same[i]) tag[i] = 1; 
				else{ FLAG=true; same[i]=1; tag[i]=1; }
			} if(FLAG) T::build();
		}
		if(op[1]=='s'){
			int l=read(),r=read(),k=read();
			cout << T::query(T::rt[l-1],T::rt[r],k,30) << '\n';
		}
	} return 0;
}
发布了634 篇原创文章 · 获赞 98 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/104084042