COGS2638. 数列操作ψ

Posted lrj998244353

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于COGS2638. 数列操作ψ的主要内容,如果未能解决你的问题,请参考以下文章

COGS-2638数列操作ψ 线段树

cogs 1317. 数列操作C 区间修改 区间查询

cogs 2632. [HZOI 2016] 数列操作d

数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列

COGS——C66. [HAOI2004模拟] 数列问题

COGS 859. 数列