看到区间修改和区间查询操作时,立马想到了线段树,这题确实可以用线段树做,因为一个数A或运算他自己的结果还是A(即A|A=A)所以区间修改操作时可以直接把所在的区间改成X,代码代码如下

    if(l<=L[x]&&r>=R[x]){
        sum[x]=data;
        return;
    }

此外与正常线段树并无太大差距了,代码如下

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000001;
int n,m,a[maxn],L[maxn<<2],R[maxn<<2],sum[maxn<<2],tag[maxn<<2],ans;
void bulid(int x,int l,int r){
    L[x]=l,R[x]=r;
    if(l==r){
        sum[x]=a[l];
        return;
    }
    int mid=l+r>>1;
    bulid(x<<1,l,mid);
    bulid(x<<1|1,mid+1,r);
    sum[x]=sum[x<<1]|sum[x<<1|1];
}
void pushdown(int x,int data){
    tag[x]=data;
    sum[x]=data;
}
void updata(int x,int l,int r,int data){
    if(r<L[x]||l>R[x]){
        return;
    }
    if(l<=L[x]&&r>=R[x]){
        sum[x]=data;
        tag[x]=data;
        return;
    }
    if(tag[x]){
        pushdown(x<<1,tag[x]);
        pushdown(x<<1|1,tag[x]);
        tag[x]=0;
    }
    updata(x<<1,l,r,data);
    updata(x<<1|1,l,r,data);
    sum[x]=sum[x<<1]|sum[x<<1|1];
}
void getsum(int x,int l,int r){
    if(r<L[x]||l>R[x]){
        return;
    }
    if(l<=L[x]&&r>=R[x]){
        ans|=sum[x];
        return;
    }
    if(tag[x]){
        pushdown(x<<1,tag[x]);
        pushdown(x<<1|1,tag[x]);
        tag[x]=0;
    }
    getsum(x<<1,l,r);
    getsum(x<<1|1,l,r);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    bulid(1,1,n);

    for(int i=1;i<=m;i++){
        int op;
        scanf("%d",&op);
        if(op==1){
            int l,r;
            scanf("%d%d",&l,&r);
            ans=0;
            getsum(1,l,r);
            printf("%d\n",ans);
        }else{
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            updata(1,l,r,k);
        }
    }
    return 0;
}