COGS2638. 数列操作ψ
COGS2638. 数列操作ψ
【题目描述】
给定一个数列a,你需要支持的操作:区间and,区间or,询问区间最大值
【输入格式】
一行两个整数n,m,表示数列长度和操作个数。
接下来一行有n个整数,第i个数表示ai。
接下来m行,每一行均为以下三种操作中的一种
1 l r val:ai=ai and val(l≤i≤r)
2 l r val:ai=ai or val(l≤i≤r)
3 l r:max{ai}(l≤i≤r)
【输出格式】
对于每一个3操作,输出一行整数表示对应的答案
【样例输入】
8 6
4 0 5 7 2 9 12 8
2 2 5 15
1 3 5 2
3 5 7
1 5 7 12
2 1 6 4
3 2 6
【样例输出】
12
15
【提示】
对于20%数据,n,m≤3000
另有20%数据,1,2操作中l=r
另有20%数据,3操作中l=r
对于100%数据,1≤n,m≤100000,0≤ai,val≤1e9
保证所有操作中1≤l≤r≤n
题解
区间And操作相当于将区间中所有数的某些位全变成0,区间Or操作相当于将区间中所有数的某些位全变成1。
线段树每个节点维护区间And和以及区间Or和,还要维护一个And标记一个Or标记以及区间最大值。
标记的先后顺序是先And后Or。
区间操作先找到区间,如果区间中所有的数要修改的那些位已经全相同,直接打上标记后返回。否则递归处理子区间。
代码
#include<bits/stdc++.h>
#define MAXN 100010
#define INF 0x7fffffff
#define lc rt<<1
#define rc rt<<1|1
namespace IO{
char buf[1<<15],*fs,*ft;
inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int qr(){
int x=0,rev=0,ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=gc();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
return rev?-x:x;}
}using namespace IO;
using namespace std;
int N,Q,tago[MAXN<<2],taga[MAXN<<2],vo[MAXN<<2],va[MAXN<<2],ma[MAXN<<2],a[MAXN];
inline void Up(int rt){
vo[rt]=vo[lc]|vo[rc];va[rt]=va[lc]&va[rc];
ma[rt]=max(ma[lc],ma[rc]);
}
inline void PutAnd(int rt,int x){
taga[rt]&=x;tago[rt]&=x;
ma[rt]&=x;vo[rt]&=x;va[rt]&=x;
}
inline void PutOr(int rt,int x){
tago[rt]|=x;
ma[rt]|=x;vo[rt]|=x;va[rt]|=x;
}
inline void Down(int rt){
if(taga[rt]^INF){
PutAnd(lc,taga[rt]);
PutAnd(rc,taga[rt]);
taga[rt]=INF;
}
if(tago[rt]){
PutOr(lc,tago[rt]);
PutOr(rc,tago[rt]);
tago[rt]=0;
}
}
void Build(int l,int r,int rt){
taga[rt]=INF;
if(l==r){va[rt]=vo[rt]=ma[rt]=a[l];return;}
int mid=(l+r)>>1;
Build(l,mid,lc);Build(mid+1,r,rc);
Up(rt);
}
void Modify(int L,int R,int l,int r,int rt,int x,bool flag){
if(L<=l&&R>=r){
if(flag){//区间&
if(((x^INF)&(va[rt]|(vo[rt]^INF)))==(x^INF)){
PutAnd(rt,x);
return;
}
}
else{//区间|
if((x&(va[rt]|(vo[rt]^INF)))==x){
PutOr(rt,x);
return;
}
}
}
Down(rt);
int mid=l+r>>1;
if(L<=mid)Modify(L,R,l,mid,lc,x,flag);
if(R>mid)Modify(L,R,mid+1,r,rc,x,flag);
Up(rt);
}
int Query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r)return ma[rt];
int mid=(l+r)>>1,ret=0;
Down(rt);
if(L<=mid)ret=Query(L,R,l,mid,lc);
if(R>mid)ret=max(ret,Query(L,R,mid+1,r,rc));
return ret;
}
int op,x,y,z;
int main(){
freopen("series_wei.in","r",stdin);
freopen("series_wei.out","w",stdout);
N=qr();Q=qr();
for(int i=1;i<=N;i++)a[i]=qr();
Build(1,N,1);
while(Q--){
op=qr();x=qr();y=qr();
if(op==1)z=qr(),Modify(x,y,1,N,1,z,1);
else if(op==2)z=qr(),Modify(x,y,1,N,1,z,0);
else printf("%d\n",Query(x,y,1,N,1));
}
return 0;
}