zoukankan      html  css  js  c++  java
  • COGS-2638 区间与,异或,询问max

    本篇题解参考了这个博客

    题目链接

    我们利用线段树来维护区间第最大值,考虑如何修改

    每一次进行与操作时只有z的二进制为0的位会产生影响

    每一次进行或操作时只有z的二进制为1的位会产生影响

    所以只要该区间二进制相同的位刚好是z会产生影响的二进制为位

    那么该修改对这个区间的影响是一样的,我们就可以用一个区间修改的标记进行维护

    标记下传也很简单

    现在的问题是如何快速合并两个区间

    我们用0表示该区间第k位二进制位不同,1表示相同

    显然可以用一个int来存下

    左右区间相同的二进制位一定是左边区间相同的和右边区间相同的二进制位的交集的子集

    显然 same[l]&same[r]就是交集 但是我们还要判断第k位在左右区间究竟是否相同

    有可能左边第k位都是0,右边第k位全是1

    我们只要左右区间各取一个代表元素,然后将这两个代表元素的相同位取出来与一下(same[l] & same[r])就好了

    复杂度度大概是nlogn

    # include<cstdio>
    # include<algorithm>
    # include<cstdlib>
    # include<ctime>
    # include<iostream>
    using namespace std;
    const int mn = 100005;
    int a[mn];
    struct segment{
        int mx[mn*4],sam[mn*4],tag[mn*4];
        int bas;
        void updown(int cur)
        {
            mx[cur]=max(mx[cur<<1],mx[cur<<1|1]);
            sam[cur]=((sam[cur<<1] & sam[cur<<1|1]) & (~(mx[cur<<1] ^ mx[cur<<1|1])));
        }
        void pushdown(int cur)
        {
             if(tag[cur])
             {
                 mx[cur<<1]+=tag[cur];
                 mx[cur<<1|1]+=tag[cur];
                 tag[cur<<1]+=tag[cur];
                 tag[cur<<1|1]+=tag[cur];
                 tag[cur]=0;
             }
        }
        void build(int l,int r,int cur)
        {
            if(l==r)
            {
                mx[cur]=a[l];
                sam[cur]=bas;
                return ;
            }
            int mid=l+r>>1;
            build(l,mid,cur<<1);
            build(mid+1,r,cur<<1|1);
            updown(cur);
        }
        bool check(int cur,int val)
        {
            int tmp=(val ^ bas);
            return (tmp & sam[cur])==tmp;
        }
        void update1(int l,int r,int cur,int L,int R,int z)
        {
            if(l>R || r<L) return ;
            if(l>=L && r<=R && check(cur,z)) {
                 int tmp = (mx[cur]  & z) - mx[cur];
                 tag[cur]+=tmp; mx[cur]+=tmp;
                 return ;
            }
            int mid=l+r>>1;
            pushdown(cur);
            update1(l,mid,cur<<1,L,R,z);
            update1(mid+1,r,cur<<1|1,L,R,z);
            updown(cur);
        }
        void update2(int l,int r,int cur,int L,int R,int z)
        {
            if(l>R || r<L) return ;
            if(l>=L && r<=R && ((z& sam[cur]) ==z)) {
                 int tmp = (mx[cur]  | z) - mx[cur];
                 tag[cur]+=tmp; mx[cur] +=tmp;
                 return ;
            }
            int mid=l+r>>1;
            pushdown(cur);
            update2(l,mid,cur<<1,L,R,z);
            update2(mid+1,r,cur<<1|1,L,R,z);
            updown(cur);
        }
        int query(int l,int r,int cur,int L,int R)
        {
            if(l>=L && r<=R) return mx[cur];
            if(l>R || r<L) return 0;
            int mid=l+r>>1;
            pushdown(cur);
            int ret=0;
            ret=max(query(l,mid,cur<<1,L,R),query(mid+1,r,cur<<1|1,L,R));
            updown(cur);
            return ret;
        }
    }T;
    int n,m;
    int main()
    {
        int opt,x,y,z;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
           scanf("%d",&a[i]);
        T.bas=2147483647;
        T.build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&opt,&x,&y);
            if(opt==1)
            {
                scanf("%d",&z);
                T.update1(1,n,1,x,y,z);
            }
            else if(opt==2)
            {
                scanf("%d",&z);
                T.update2(1,n,1,x,y,z);
            }
            else printf("%d
    ",T.query(1,n,1,x,y));
        }
        return 0;
    }
  • 相关阅读:
    公司程序升级 win2008
    软件
    crystal 2008升级(草稿)
    crystalreportviewers12的一些修改
    Crystal Report 2008
    deep learning 相关资料 Lei
    如何打印出符合acm要求的pdf Lei
    matlab常用命令 Lei
    Wilson Interval Lei
    Perl / Shell 脚本语言 Lei
  • 原文地址:https://www.cnblogs.com/logeadd/p/9361402.html
Copyright © 2011-2022 走看看