「雅礼集训 2018 Day7」A - 题解
题解:
线段树处理。
考虑只有一种与的操作。显然当一个区间的或和与上将要与的数还是原数时就没必要递归计算了,剪枝剪掉。当一段区间与和与上将要与的数等于这段区间或和与上将要与的数时,更新后这段区间的最小值位置还是更新前的位置。由于一次操作至少将数的一个二进制改变,所以最多改变 \(\log {INT_{MAX}}\) 次,时间复杂度\(O(n \times \log {INT_{MAX}} \times \log {n})\)。
当存在两个修改操作时同样操作即可。
代码:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=500010,MX=2147483647;
int n,m,a[N];
struct P { int v,Or,And; };P t[N<<2];
int lz_or[N<<2],lz_and[N<<2];
template <typename T> inline void read(T &x) {
x=0;re char c=getchar();while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=x*10+(c^48),c=getchar();
}
inline int Min(const int &x,const int &y) { return x<y? x:y; }
P pushup(P ls,P rs) {
P tt; tt.Or=ls.Or|rs.Or,tt.And=ls.And&rs.And;
tt.v=Min(ls.v,rs.v); return tt;
}
void push_or(int u,int w) {
lz_or[u]|=w,lz_and[u]|=w,t[u].v|=w,t[u].Or|=w,t[u].And|=w;
}
void push_and(int u,int w) {
lz_or[u]&=w,lz_and[u]&=w,t[u].v&=w,t[u].Or&=w,t[u].And&=w;
}
void pushdown(int u) {
if(lz_or[u]) {
push_or(u*2,lz_or[u]),push_or(u*2+1,lz_or[u]);
lz_or[u]=0;
}
if(lz_and[u]!=MX) {
push_and(u*2,lz_and[u]),push_and(u*2+1,lz_and[u]);
lz_and[u]=MX;
}
}
void build(int u,int l,int r) {
lz_or[u]=0,lz_and[u]=MX;
if(l>=r) { t[u].Or=t[u].And=t[u].v=a[l];return ; }
int mid=(l+r)>>1; build(u*2,l,mid),build(u*2+1,mid+1,r);
t[u]=pushup(t[u*2],t[u*2+1]);
}
void mdy_and(int u,int l,int r,int L,int R,int w) {
if((t[u].Or&w)==t[u].Or) return ;
if(l==L&&r==R&&(t[u].And&w)==(t[u].Or&w))
{ push_and(u,w);return ; }
int mid=(l+r)>>1; pushdown(u);
if(R<=mid) mdy_and(u*2,l,mid,L,R,w);
else if(L>mid) mdy_and(u*2+1,mid+1,r,L,R,w);
else mdy_and(u*2,l,mid,L,mid,w),mdy_and(u*2+1,mid+1,r,mid+1,R,w);
t[u]=pushup(t[u*2],t[u*2+1]);
}
void mdy_or(int u,int l,int r,int L,int R,int w) {
if((t[u].And|w)==t[u].And) return ;
if(l==L&&r==R&&(t[u].And|w)==(t[u].Or|w))
{ push_or(u,w);return ; }
int mid=(l+r)>>1; pushdown(u);
if(R<=mid) mdy_or(u*2,l,mid,L,R,w);
else if(L>mid) mdy_or(u*2+1,mid+1,r,L,R,w);
else mdy_or(u*2,l,mid,L,mid,w),mdy_or(u*2+1,mid+1,r,mid+1,R,w);
t[u]=pushup(t[u*2],t[u*2+1]);
}
int qry(int u,int l,int r,int L,int R) {
if(l==L&&r==R) return t[u].v;
int mid=(l+r)>>1; pushdown(u);
if(R<=mid) return qry(u*2,l,mid,L,R);
if(L>mid) return qry(u*2+1,mid+1,r,L,R);
return Min(qry(u*2,l,mid,L,mid),qry(u*2+1,mid+1,r,mid+1,R));
}
int main() {
int opt,l,r,z;
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]);
build(1,1,n);
for(;m;--m) {
read(opt),read(l),read(r);
switch(opt) {
case 1: read(z),mdy_and(1,1,n,l,r,z);break;
case 2: read(z),mdy_or(1,1,n,l,r,z);break;
default: printf("%d\n",qry(1,1,n,l,r));break;
}
// printf("<<< ");
// for(int i=1;i<=n;i++) printf("%d ",qry(1,1,n,i,i));
// printf("\n");
}
return 0;
}