• COGS 2638. 数列操作ψ 线段树


    传送门 : COGS 2638. 数列操作ψ 线段树

    这道题让我们维护区间最大值,以及维护区间and,or一个数
    我们考虑用线段树进行维护,这时候我们就要用到吉司机线段树啦 QAQ

    由于发现若干次and,or之后,如果数据分布均匀,那么几乎所有的数在若干次操作后都会变成同一个数
    因为我们的and操作中的0位,以及or操作当中的1位,都是可以把整个区间的那一二进制位重置为相同的
    我们考虑利用这一个性质
    如果我们直接维护一个区间内的值是否是相同的,那么效果会差很多。
    我们发现我们在进行and操作的时候只有为0的二进制位才可能更改原本的二进制位
    同样的,在进行or操作的时候也只有为1的二进制位才可能更改原本的二进制位

    所以我们可以在区间内所有的数的对应的会做出修改的二进制位完全相同时作出区间整体修改
    至于区间整体修改,我们很容易发现,实际上就是区间内加上一个数

    所以对于每一个线段树节点,维护一个sam值,表示这个线段树代表的区间内二进制位的相同情况
    对应二进制位为1,则代表区间内所有值的这一位都是相同的

    随后我们通过对区间内所有元素对应二进制位是否相同的情况来判断是否可以进行区间修改即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    inline void read(int &x){
        x=0;static char ch;static bool flag;flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    #define rg register int
    #define rep(i,a,b) for(rg i=(a);i<=(b);++i)
    #define per(i,a,b) for(rg i=(a);i>=(b);++i)
    const int maxn = 100010;
    const int bas = 0x7fffffff;
    int T[maxn<<2],lazy[maxn<<2],sam[maxn<<2];
    int a[maxn];
    inline void update(int rt){
        T[rt] = max(T[rt<<1],T[rt<<1|1]);
        sam[rt] = (sam[rt<<1]&sam[rt<<1|1]) & (~(T[rt<<1]^T[rt<<1|1]));
    }
    inline void pushdown(int rt){
        if(lazy[rt] == 0) return ;
        T[rt<<1] += lazy[rt];lazy[rt<<1] += lazy[rt];
        T[rt<<1|1] += lazy[rt];lazy[rt<<1|1] += lazy[rt];
        lazy[rt] = 0;
    }
    void build(int rt,int l,int r){
        if(l == r){
            T[rt] = a[l];
            sam[rt] = bas;
            return ;
        }int mid = l+r >> 1;
        build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
        update(rt);
    }
    int L,R,val,tmp;
    inline bool check_a(int rt){
        tmp = (val^bas);
        return (tmp & sam[rt]) == tmp;
    }
    void modify_a(int rt,int l,int r){
        if(L <= l && r <= R && check_a(rt)){
            tmp = (T[rt] & val) - T[rt];
            lazy[rt] += tmp;T[rt] += tmp;
            return ;
        }int mid = l+r >> 1;pushdown(rt);
        if(L <= mid) modify_a(rt<<1,l,mid);
        if(R >  mid) modify_a(rt<<1|1,mid+1,r);
        update(rt);
    }
    void modify_o(int rt,int l,int r){
        if(L <= l && r <= R && (sam[rt] & val) == val){
            tmp = (T[rt] | val) - T[rt];
            lazy[rt] += tmp;T[rt] += tmp;
            return ;
        }int mid = l+r >> 1;pushdown(rt);
        if(L <= mid) modify_o(rt<<1,l,mid);
        if(R >  mid) modify_o(rt<<1|1,mid+1,r);
        update(rt);
    }
    int query(int rt,int l,int r){
        if(L <= l && r <= R) return T[rt];
        int mid = l+r >> 1;pushdown(rt);
        if(R <= mid) return query(rt<<1,l,mid);
        if(L >  mid) return query(rt<<1|1,mid+1,r);
        return max(query(rt<<1,l,mid),query(rt<<1|1,mid+1,r));
    }
    int main(){
        //freopen("series_wei.in","r",stdin);
        //freopen("series_wei.out","w",stdout);
        int n,m;read(n);read(m);
        rep(i,1,n) read(a[i]);
        build(1,1,n);int opt;
        int cnt = 0 ;
        while(m--){
            read(opt);read(L);read(R);
            if(opt == 1) read(val),modify_a(1,1,n);
            else if(opt == 2) read(val),modify_o(1,1,n);
            else printf("%d
    ",query(1,1,n));
        }
        return 0;
    }
    
  • 相关阅读:
    docker 应用-1(安装以及基础命令)
    网桥原理及使用
    【年终总结】个人的2019年年终总结
    【bat批处理】批量执行某个文件夹下的所有sql文件bat批处理
    【实用工具】.fbr格式免费播放器 FBR格式 Free FlashBack Player
    【SQL骚操作】SqlServer数据库表生成C# Model实体类SQL语句
    【算法基础】面试过程中遇到的一些算法题输出杨辉三角
    【sql基础】按照名字分组查询时间最早的一条记录
    【面试题】java面试题整理(有空再贴答案)
    【海驾资料】海淀驾校科目三考试资料
  • 原文地址:https://www.cnblogs.com/Skyminer/p/9185768.html
Copyright © 2020-2023  润新知