题目传送门
分析:
这里 与 和 或 两种运算明显可以近似处理,我们先考虑 与 的情况
设目前要 与 的值为\(x\)
如果一个区间的 或和 与上 \(x\)为它本身,那么这次操作在这个区间上就没有用,不用向下处理了
如果一个区间的 或和 与上 \(x\)等于这个区间的 与和 与上 \(x\),那么这次操作对这个区间的最小值不会有影响,打上懒标记
这个操作会至少修改区间上的一位,那么一个区间至多会被修改32次
或 操作用类似的方式维护就好了
复杂度\(O(nlognlogA)\)
(INF开的\(2^{30}\)导致直接爆零,一定要注意!)
#include
#include
#include
#include
#define maxn 500005
#define INF 2147483647
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m;
int a[maxn];
int mn[maxn<<2],s1[maxn<<2],s2[maxn<<2],lz1[maxn<<2],lz2[maxn<<2];
inline void pushup(int i)
{
mn[i]=min(mn[i<<1],mn[i<<1|1]);
s1[i]=s1[i<<1]&s1[i<<1|1];
s2[i]=s2[i<<1]|s2[i<<1|1];
}
inline void work1(int i,int num)
{lz1[i]&=num,lz2[i]&=num,mn[i]&=num,s1[i]&=num,s2[i]&=num;}
inline void work2(int i,int num)
{lz1[i]|=num,lz2[i]|=num,mn[i]|=num,s1[i]|=num,s2[i]|=num;}
inline void pushdown(int i)
{
if(lz1[i]!=INF)
{
work1(i<<1,lz1[i]),work1(i<<1|1,lz1[i]);
lz1[i]=INF;
}
if(lz2[i])
{
work2(i<<1,lz2[i]),work2(i<<1|1,lz2[i]);
lz2[i]=0;
}
}
inline void build(int i,int l,int r)
{
lz1[i]=INF,lz2[i]=0;
if(l==r){mn[i]=s1[i]=s2[i]=a[l];return;}
int mid=(l+r)>>1;
build(i<<1,l,mid),build(i<<1|1,mid+1,r);
pushup(i);
}
inline void update1(int i,int l,int r,int ql,int qr,int num)
{
if(r>1;
update1(i<<1,l,mid,ql,qr,num),update1(i<<1|1,mid+1,r,ql,qr,num);
pushup(i);
}
inline void update2(int i,int l,int r,int ql,int qr,int num)
{
if(r>1;
update2(i<<1,l,mid,ql,qr,num),update2(i<<1|1,mid+1,r,ql,qr,num);
pushup(i);
}
inline int query(int i,int l,int r,int ql,int qr)
{
if(r>1;
return min(query(i<<1,l,mid,ql,qr),query(i<<1|1,mid+1,r,ql,qr));
}
int main()
{
n=getint(),m=getint();
for(int i=1;i<=n;i++)a[i]=getint();
build(1,1,n);
while(m--)
{
int op=getint();
if(op==1)
{
int l=getint(),r=getint(),x=getint();
update1(1,1,n,l,r,x);
}
if(op==2)
{
int l=getint(),r=getint(),x=getint();
update2(1,1,n,l,r,x);
}
if(op==3)
{
int l=getint(),r=getint();
printf("%d\n",query(1,1,n,l,r));
}
}
}