zoukankan      html  css  js  c++  java
  • NOI2017整数

    原题链接

    发现进位或退位时,会有连续的一段1变成0或连续的0变成1,然后在后面产生一个进位或退位。于是我们只需要一颗线段树支持区间赋值,查询左边第一个1/0,以及单点查询值。可以把a按二进制拆开去修改,复杂度是O(nlognloga)的,这样好像过不去。

    于是我的做法是在线段树的每个叶子节点存30位,用一个int保存,修改时就只需将a拆成跨过叶子节点的两部分,每部分直接加到对应的叶子节点,若超过了$2^{30}-1$就往前进一位即可(减法的话就看减去以后有没有小于0,有就向前借一位),复杂度O(nlogn)。

    查询左边第一个0/1时,可以维护每个区间是全为1/全为0/又有0又有1。

    UPD: WC上机练习时重新打了一遍代码,原来的代码又丑又慢。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define Pputs("lala")
    #define cpcerr<<"lala"<<endl
    #define fi first
    #define se second
    #define lnputchar('
    ')
    #define pbpush_back
    using namespace std;
    inline int read()
    {
        char ch=getchar(); int g=1,re=0;
        while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
        while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
        return re*g;
    }
    typedef long long ll;
    typedef pair<int,int>pii;
    typedef unsigned int ui;
    
    const int N=1005000;
    int all[2]={0,(1<<30)-1};
    const int both=85490;
    
    int n,sum[N<<2],setv[N<<2];
    
    void pushdown(int o)
    {
        if(setv[o]!=-1)
        {
            setv[o<<1]=setv[o]; setv[o<<1|1]=setv[o];
            sum[o<<1]=all[setv[o]]; sum[o<<1|1]=all[setv[o]];
            setv[o]=-1;
        }
    }
    
    int jin=0,found=0,ret=-1;
    
    namespace add
    {
        void update(int o,int l,int r,int b,int x)
        {
            if(l==r)
            {
                sum[o]+=x;
                if(sum[o]>all[1]) sum[o]&=all[1],jin=1;
                return ;
            }
            pushdown(o);
            int mid=l+r>>1;
            if(b<=mid) update(o<<1,l,mid,b,x);
            else update(o<<1|1,mid+1,r,b,x);
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
        void gonex(int o,int l,int r)
        {
            if(l==r)
            {
                ret=l-1;
                for(int i=0;i<30;++i)
                    if(sum[o]&1<<i) sum[o]^=1<<i;
                    else {sum[o]^=1<<i;break;}
                return ;
            }
            pushdown(o);
            int mid=l+r>>1;
            if(sum[o<<1]!=all[1]) gonex(o<<1,l,mid);
            else gonex(o<<1|1,mid+1,r);
    
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
        void findnex(int o,int l,int r,int x,int y)
        {
            if(found) return ;
            if(x<=l&&r<=y)
            {
                if(sum[o]!=all[1]) found=1,gonex(o,l,r);
                return ;
            }
            pushdown(o);
            int mid=l+r>>1;
            if(x<=mid) findnex(o<<1,l,mid,x,y);
            if(y>mid) findnex(o<<1|1,mid+1,r,x,y);
    
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
        void modify(int o,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y) {setv[o]=0;sum[o]=all[0];return ;}
            pushdown(o);
            int mid=l+r>>1;
            if(x<=mid) modify(o<<1,l,mid,x,y);
            if(y>mid) modify(o<<1|1,mid+1,r,x,y);
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
    }
    
    namespace sub
    {
        void update(int o,int l,int r,int b,int x)
        {
            if(l==r)
            {
                sum[o]-=x;
                if(sum[o]<0) sum[o]+=all[1]+1,jin=1;
                return ;
            }
            pushdown(o);
            int mid=l+r>>1;
            if(b<=mid) update(o<<1,l,mid,b,x);
            else update(o<<1|1,mid+1,r,b,x);
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
        void gonex(int o,int l,int r)
        {
            if(l==r)
            {
                ret=l-1;
                for(int i=0;i<30;++i)
                    if(!(sum[o]&1<<i)) sum[o]^=1<<i;
                    else {sum[o]^=1<<i;break;}
                return ;
            }
            pushdown(o);
            int mid=l+r>>1;
            if(sum[o<<1]!=all[0]) gonex(o<<1,l,mid);
            else gonex(o<<1|1,mid+1,r);
    
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
        void findnex(int o,int l,int r,int x,int y)
        {
            if(found) return ;
            if(x<=l&&r<=y)
            {
                if(sum[o]!=all[0]) found=1,gonex(o,l,r);
                return ;
            }
            pushdown(o);
            int mid=l+r>>1;
            if(x<=mid) findnex(o<<1,l,mid,x,y);
            if(y>mid) findnex(o<<1|1,mid+1,r,x,y);
    
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
        void modify(int o,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y) {setv[o]=1;sum[o]=all[1];return ;}
            pushdown(o);
            int mid=l+r>>1;
            if(x<=mid) modify(o<<1,l,mid,x,y);
            if(y>mid) modify(o<<1|1,mid+1,r,x,y);
            if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1];
            else sum[o]=both;
        }
    }
    
    int query(int o,int l,int r,int k)
    {
        if(l==r) return sum[o]>>(k%30)&1;
        pushdown(o);
        int mid=l+r>>1;
        if(k/30<=mid) return query(o<<1,l,mid,k);
        else return query(o<<1|1,mid+1,r,k);
    }
    
    void wj()
    {
        freopen("integer.in","r",stdin);
        freopen("integer.out","w",stdout);
    }
    int main()
    {
        //wj();
        memset(setv,-1,sizeof(setv));
        n=read(); read(); read(); read();
        for(int cas=1;cas<=n;++cas)
        {
            int opt=read();
            if(opt==1)
            {
                int a=read(),b=read();
                if(!a) continue;
    
                if(a>0)
                {
                    jin=0; ret=-1; found=0;
                    add::update(1,0,n,b/30,(a<<(b%30))&all[1]);
                    if(jin&&b/30<n) add::findnex(1,0,n,b/30+1,n);
                    if(b/30+1<=ret) add::modify(1,0,n,b/30+1,ret);
    
                    if(!(a>>(30-b%30))) continue;
                    jin=0; ret=-1; found=0;
                    add::update(1,0,n,b/30+1,a>>(30-b%30));
                    if(jin&&b/30+1<n) add::findnex(1,0,n,b/30+2,n);
                    if(b/30+2<=ret) add::modify(1,0,n,b/30+2,ret);
                }
                else
                {
                    a=-a;
                    jin=0; ret=-1; found=0;
                    sub::update(1,0,n,b/30,(a<<(b%30))&all[1]);
                    if(jin&&b/30<n) sub::findnex(1,0,n,b/30+1,n);
                    if(b/30+1<=ret) sub::modify(1,0,n,b/30+1,ret);
    
                    if(!(a>>(30-b%30))) continue;
                    jin=0; ret=-1; found=0;
                    sub::update(1,0,n,b/30+1,a>>(30-b%30));
                    if(jin&&b/30+1<n) sub::findnex(1,0,n,b/30+2,n);
                    if(b/30+2<=ret) sub::modify(1,0,n,b/30+2,ret);
                }
            }
            else
            {
                int k=read();
                printf("%d
    ",query(1,0,n,k));
            }
        }
        return 0;
    }
  • 相关阅读:
    Mac 自带 apache 服务器
    比较器Comparable Comparator
    深入学习二叉树(01)完全二叉树
    深入学习二叉树(02)线索二叉树
    深入学习二叉树(06)霍夫曼树/哈夫曼编码/最优二叉树
    深入学习二叉树(05)红黑树
    深入学习二叉树(07)B树
    Java 1.8 红黑树
    ConcurrentHashMap 结构 1.7 与1.8
    git 操作详情
  • 原文地址:https://www.cnblogs.com/thkkk/p/7647740.html
Copyright © 2011-2022 走看看