「雅礼集训 2018 Day7」A 题解 (线段树,二进制)

题目简介

给定一个长度为 \(n\) 的序列 \(A_i\),下标从 \(1\) 开始。对其依次进行 \(m\) 次操作或询问,分为 \(3\) 种类型:

  • 1 l r x:将 \(A_{l...r}\) 中每个元素二进制与上一个数 \(x\)
  • 2 l r x:将 \(A_{l...r}\) 中每个元素二进制或上一个数 \(x\)
  • 3 l r:求 \(A_{l...r}\) 中的最小值

分析

线段树维护三个变量:\(va\)\(vo\)\(mn\)

\(va\) 表示区间和,\(vo\) 表示区间或,\(mn\) 表示区间最小值。

\(\mbox{S}(x)\) 表示 \(x\) 中二进制位为 \(1\) 的位置的集合,\(x(b)\) 表示 \(x\) 二进制下第 \(b\) 位。

对于 \(1\) 操作来看,及 \([l,r]\ \mbox{and}\ k\),有以下结论:

  • \(vo\ \mbox{and}\ k = vo\),则区间中所有数二进制位为 \(1\) 的,\(k\) 的相应位置也是 \(1\),此时该操作无效。

    道理很简单,\(vo\ \mbox{and}\ k = vo\),则\(\mbox{S}(vo)\subseteq\mbox{S}(k)\) ,而 \(\forall x\in[l,r],\ \mbox{S}(x)\subseteq\mbox{S}(vo)\),所以 \(\mbox{S}(x)\subseteq\mbox{S}(k)\)

  • \(vo\ \mbox{and}\ k = va\ \mbox{and}\ k = t\),则区间中所有数操作后相等。

    显然,\(\mbox{S}(va)\subseteq\mbox{S}(vo)\)。而 \(vo\ \mbox{and}\ k = va\ \mbox{and}\ k\),所以一旦\(b\in\mbox{S}(vo),b\notin\mbox{S}(va)\),则 \(k(b)=0\)

    对于区间中一个数 \(x\)

    • 如果 \(x(b)=1\),则 \(b\in\mbox{S}(va)\)\(x(b)\ \mbox{and}\ k=t(b)\)
    • 否则如果 \(x(b)=0\),若\(b\in\mbox{S}(vo)\),则 \(k(b) =0\)\(x(b)\ \mbox{and}\ k=t(b)=0\)
    • 否则 \(b\notin\mbox{S}(vo)\)\(x(b)\ \mbox{and}\ k=t(b)\)
  • 不断递归下去,一定有一个子区间满足上述两个条件,极限当 \(l=r\) 时,一定满足第二个条件。

对于 \(2\) 操作来看,及\([l,r]\ \mbox{or}\ k\),有一下结论:

  • \(va\ \mbox{or}\ k=va\),,则区间中所有数二进制位全为 \(1\) 的,\(k\) 的相应位置也是 \(1\),此时该操作无效。

    证明方法类似上述第一个结论。\(\mbox{S}(k)\subseteq\mbox{S}(va),\mbox{S}(va)\subseteq\mbox{S}(x)\)\(\mbox{S}(k)\subseteq\mbox{S}(x)\)

  • \(va\ \mbox{or}\ k=vo\ \mbox{or}\ k = t\),则区间中所有数操作后相等。

    证明方法类似上述第二个结论,不再赘述。

  • 不断递归下去,一定有一个子区间满足上述两个条件,极限当 \(l=r\) 时,一定满足第二个条件。

时间复杂度玄学,笔者不会证明/kk

\(AC\ Code\)

#include<cstdio>
#include<iostream>
using namespace std;
const int Maxn=5e5+5;
const int E=0x7fffffff;
struct segtree{
	int l,r;
	int va,vo,mn;
	int ta,to;
}tr[Maxn<<2];
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
inline void pushup(int x){
	tr[x].va=tr[ls(x)].va&tr[rs(x)].va;
	tr[x].vo=tr[ls(x)].vo|tr[rs(x)].vo;
	tr[x].mn=min(tr[ls(x)].mn,tr[rs(x)].mn);
}
inline void tag_and(int x,int c){
	tr[x].va&=c,tr[x].vo&=c,tr[x].mn&=c;
	tr[x].ta&=c,tr[x].to&=c;
}
inline void tag_or (int x,int c){
	tr[x].va|=c,tr[x].vo|=c,tr[x].mn|=c;
	tr[x].ta|=c,tr[x].to|=c;
}
inline void pushdown(int x){
	if(tr[x].ta!=E)tag_and(ls(x),tr[x].ta),tag_and(rs(x),tr[x].ta);
	if(tr[x].to!=0)tag_or (ls(x),tr[x].to),tag_or (rs(x),tr[x].to);
	tr[x].ta=E,tr[x].to=0;
}
int a[Maxn];
void build(int x,int L,int R){
	tr[x].l=L,tr[x].r=R;tr[x].ta=E;
	if(L==R){tr[x].va=tr[x].vo=tr[x].mn=a[L];return ;}
	int mid=L+R>>1;
	build(ls(x),L,mid);
	build(rs(x),mid+1,R);
	pushup(x);
}
void modify_and(int x,int ql,int qr,int d){
	if((tr[x].vo&d)==tr[x].vo)return ;
	if(ql<=tr[x].l&&tr[x].r<=qr)
		if((tr[x].vo&d)==(tr[x].va&d))return tag_and(x,d);
	pushdown(x);
	int mid=tr[x].l+tr[x].r>>1;
	if(ql<=mid)modify_and(ls(x),ql,qr,d);
	if(qr> mid)modify_and(rs(x),ql,qr,d);
	pushup(x);
}
void modify_or (int x,int ql,int qr,int d){
	if((tr[x].va|d)==tr[x].va)return ;
	if(ql<=tr[x].l&&tr[x].r<=qr)
		if((tr[x].va|d)==(tr[x].vo|d))return tag_or (x,d);
	pushdown(x);
	int mid=tr[x].l+tr[x].r>>1;
	if(ql<=mid)modify_or (ls(x),ql,qr,d);
	if(qr> mid)modify_or (rs(x),ql,qr,d);
	pushup(x);
}
int query(int x,int ql,int qr){
	if(ql<=tr[x].l&&tr[x].r<=qr)return tr[x].mn;
	pushdown(x);
	int mid=tr[x].l+tr[x].r>>1;
	if(qr<=mid)return query(ls(x),ql,qr);
	if(ql> mid)return query(rs(x),ql,qr);
	return min(query(ls(x),ql,qr),query(rs(x),ql,qr));
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;++i)cin>>a[i];
	build(1,1,n);
	while(m--){
		int op,l,r,d;cin>>op>>l>>r;
		if(op==1)cin>>d,modify_and(1,l,r,d);
		if(op==2)cin>>d,modify_or (1,l,r,d);
		if(op==3)cout<<query(1,l,r)<<'\n';
	}
	return 0;
}

$$-----EOF-----$$

posted @ 2023-02-24 11:45  AlienCollapsar  阅读(56)  评论(0编辑  收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq