题意:
给出一个序列,两种操作。
0 L R:查询[L,R]中的最小值
1 L R X:[L,R]中的每个数与X进行与操作
思路:
线段树
重点:state变量记录某区间的一种状态,当某节点的state&X==state时,说明不变,这时return,因为下面做的是无用功;否则当该节点只是单纯的一个点,进行与操作,修改state变量。
push_up()操作:或操作
tree[id].state=tree[id2].state|tree[id2+1].state
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#define inf 0x7fffffff
using namespace std;
int n,m,a[100005];
struct node
{
int l,r,mi,state;
} tree[100005*4];
void push_up(int id)
{
tree[id].mi=min(tree[id*2].mi,tree[id*2+1].mi);
tree[id].state=tree[id*2].state|tree[id*2+1].state;
}
void build(int id,int l,int r)
{
tree[id].l=l;
tree[id].r=r;
if(l==r)
{
tree[id].mi=tree[id].state=a[l];
return;
}
int mid=l+(r-l)/2;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
push_up(id);
}
void update(int id,int l,int r,int x)
{
int L=tree[id].l,R=tree[id].r;
if(l<=L&&R<=r)
{
int t=tree[id].state&x;
if(t==tree[id].state)
return;
}
if(L==R)
{
tree[id].mi=tree[id].mi&x;
tree[id].state=tree[id].mi;
return;
}
if(tree[id*2].r>=l)
{
update(id*2,l,r,x);
}
if(tree[id*2+1].l<=r)
{
update(id*2+1,l,r,x);
}
push_up(id);
}
int query(int id,int l,int r)
{
int L=tree[id].l,R=tree[id].r;
if(l<=L&&R<=r)
{
return tree[id].mi;
}
if(l>R||r<L)
return inf;
int ans=inf;
if(tree[id*2].r>=l)
{
ans=min(ans,query(id*2,l,r));
}
if(tree[id*2+1].l<=r)
{
ans=min(ans,query(id*2+1,l,r));
}
return ans;
}
int main()
{
int l,r,z,x;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
build(1,1,n);
while(m--)
{
scanf("%d%d%d",&z,&l,&r);
if(z==0)
{
printf("%d\n",query(1,l,r));
}
else
{
scanf("%d",&x);
update(1,l,r,x);
}
}
}
return 0;
}