suxxsfe

一言(ヒトコト)

LOJ6507 「雅礼集训 2018 Day7」A

https://loj.ac/p/6507

考虑线段树维护区间或 \(o\) 和区间与 \(a\),对于区间和 \(k\) 与的操作:

  • \(o \operatorname{and} k=o\),则说明每个此区间有 \(1\) 的位 \(k\) 也都是 \(1\),操作在此区间没用
  • \(o \operatorname{and} k=a \operatorname{and} k\),则说明 \(k\) 只在区间所有数 都有 或 都没有 \(1\) 的位置上有 \(1\),那么可以打标记的同时维护最小值
  • 其他情况递归下去

或操作类似

关于复杂度,设 \(u\) 节点的势能是 满足区间中存在两数的这一二进制位不同 的二进制位数
那么初始势能是 \(O(n\log n\log A)\),每次修改操作会增加最多 \(O(\log n\log A)\) 的势能
而每次暴力递归一层,至少会减少 \(1\) 的势能,因此复杂度 \(O(n\log n\log A)\)


#define lim 2147483647
#define N 500006
struct Node{
	Node *ls,*rs;
	int _and,_or,min;
	int tand,tor;
	inline void pushup(){
		min=std::min(ls->min,rs->min);
		_and=ls->_and&rs->_and;_or=ls->_or|rs->_or;
	}
	inline void And(int k){_and&=k;_or&=k;min&=k;tand&=k;tor&=k;}
	inline void Or(int k){_and|=k;_or|=k;min|=k;tand|=k;tor|=k;}
	inline void pushdown(){
		ls->And(tand);ls->Or(tor);
		rs->And(tand);rs->Or(tor);
		tand=lim;tor=0;
	}
}dizhi[N*2],*root;int tot;
int a[N];
void build(Node *&tree,int l,int r){
	tree=&dizhi[++tot];
	tree->tand=lim;
	if(l==r) return tree->_and=tree->_or=tree->min=a[l],void();
	int mid=(l+r)>>1;
	build(tree->ls,l,mid);build(tree->rs,mid+1,r);
	tree->pushup();
}
void And(Node *tree,int l,int r,int ql,int qr,int k){
	if((tree->_or&k)==tree->_or) return;
	if(ql<=l&&r<=qr&&(tree->_and&k)==(tree->_or&k)) return tree->And(k),void();
	tree->pushdown();
	int mid=(l+r)>>1;
	if(ql<=mid) And(tree->ls,l,mid,ql,qr,k);
	if(qr>mid) And(tree->rs,mid+1,r,ql,qr,k);
	tree->pushup();
}
void Or(Node *tree,int l,int r,int ql,int qr,int k){
	if((tree->_and|k)==tree->_and) return;
	if(ql<=l&&r<=qr&&(tree->_and|k)==(tree->_or|k)) return tree->Or(k),void();
	tree->pushdown();
	int mid=(l+r)>>1;
	if(ql<=mid) Or(tree->ls,l,mid,ql,qr,k);
	if(qr>mid) Or(tree->rs,mid+1,r,ql,qr,k);
	tree->pushup();
}
int getMin(Node *tree,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr) return tree->min;
	tree->pushdown();
	int mid=(l+r)>>1,ans=lim;
	if(ql<=mid) ans=getMin(tree->ls,l,mid,ql,qr);
	if(qr>mid) ans=std::min(ans,getMin(tree->rs,mid+1,r,ql,qr));
	return ans;
}
int main(){
//		freopen("1.in","r",stdin);
	int n=read(),m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	build(root,1,n);
	while(m--){
		int op=read(),l=read(),r=read();
		if(op==1) And(root,1,n,l,r,read());
		else if(op==2) Or(root,1,n,l,r,read());
		else if(op==3) printf("%d\n",getMin(root,1,n,l,r));
	}
	return 0;
}
posted @ 2021-10-10 12:10  suxxsfe  阅读(165)  评论(0编辑  收藏  举报