• NOI 2017 D1T1 整数 压位 线段树


    $ Rightarrow $ 戳我进洛谷原题 $ Rightarrow $ 戳我进BZOJ原题

    [Noi2017]整数

    时空限制 $ quad $ 2000ms / 512MB

     

    题目背景

    在人类智慧的山巅,有着一台字长为 $ 1048576 $ 位(此数字与解题无关)的超级计算机,
    著名理论计算机科学家P博士正用它进行各种研究。不幸的是,这天台风切断了电力系统,
    超级计算机无法工作,而 P 博士明天就要交实验结果了,只好求助于学过OI的你. . . . . .
     

    题目描述

    P 博士将他的计算任务抽象为对一个整数的操作。具体来说,有一个整数 $ x $ ,一开始为 $ 0 $ 。

    接下来有 $ n $ 个操作,每个操作都是以下两种类型中的一种:

    • 1 a b :将 $ x $ 加上整数 $ acdot 2^b $ ,其中 $ a $ 为一个整数,$ b $ 为一个非负整数

    • 2 k :询问 $ x $ 在用二进制表示时,位权为 $ 2^k $ 的位的值(即这一位上的 $ 1 $ 代表 $ 2^k $ )

    保证在任何时候,$ x geqslant 0 $ 。
     

    输入输出格式

    输入格式:

    输入的第一行包含四个正整数 $ n,t_1,t_2,t_3 $ ,$ n $ 的含义见题目描述, $ t_1,t_2,t_3 $ 的具体含义见子任务。

    接下来 $ n $ 行,每行给出一个操作,具体格式和含义见题目描述。

    同一行输入的相邻两个元素之间,用恰好一个空格隔开。

    输出格式:

    对于每个询问操作,输出一行,表示该询问的答案( $ 0 $ 或 $ 1 $ )。对于加法操作,没有任何输出。
     

    输入输出样例

    输入样例

     10 3 1 2
     1 100 0
     1 2333 0
     1 -233 0
     2 5
     2 7
     2 15
     1 5 15
     2 15
     1 -1 12
     2 15
    

    输出样例

     0
     1
     0
     1
     0
    

     

    说明

    在所有测试点中,$ 1leqslant t_1 leqslant 3, 1 leqslant t_2 leqslant 4, 1 leqslant t_3 leqslant 2 $ 。不同的 $ t_1,t_2,t_3 $ 对应的特殊限制如下:

    • 对于 $ t_1 = 1 $ 的测试点,满足 $ a = 1 $
    • 对于 $ t_1 = 2 $ 的测试点,满足 $ |a| = 1 $
    • 对于 $ t_1 = 3 $ 的测试点,满足 $ |a| leqslant 10^9 $
    • 对于 $ t_2 = 1 $ 的测试点,满足 $ 0 leqslant b, k leqslant 30 $
    • 对于 $ t_2 = 2 $ 的测试点,满足 $ 0 leqslant b, k leqslant 100 $
    • 对于 $ t_2 = 3 $ 的测试点,满足 $ 0 leqslant b, k leqslant n $
    • 对于 $ t_2 = 4 $ 的测试点,满足 $ 0 leqslant b, k leqslant 30n $
    • 对于 $ t_3 = 1 $ 的测试点,保证所有询问操作都在所有修改操作之后
    • 对于 $ t_3 = 2 $ 的测试点,不保证询问操作和修改操作的先后顺序

    本题共 25 个测试点,每个测试点 4 分。各个测试点的数据范围如下:

    pic

    思路

    • 本题需要用到线段树+压位。

    • 首先考虑在某一位加1或减1的情况。
      在加1时,我们要从当前位开始,找到最低的为0的位,然后把这一位加1,路上经过的所有位都清零。
      在减1时,我们要从当前位开始,找到最低的为1的位,然后把这一位减1,路上经过的所有位都修改成1。
      这些操作显然可以在线段树上完成。

    • 但是我们发现,操作的数位的范围可能特别大,达到 $ 3 imes 10^7 $ , $ O(n imes log_n ) $ 的时间复杂度并不能承受。
      那么我们可以把30个二进制位压成一位,或者甚至把60个二进制位压成一位,
      然后在操作的时候,原来的找0就变成了找第一个全不是1的段,原来的找1就变成了找第一个全不是0的段,
      那么压位后一次修改最多涉及两次操作,常数大大降低,就可以通过此题了。
       

    代码

    /**************************************************************
        Problem: 4942
        User: PotremZ
        Language: C++
        Result: Accepted
        Time:23424 ms
        Memory:48168 kb
    ****************************************************************/
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 1000005
    const int INF=(1<<30)-1;
    int n,sor[N<<2],sad[N<<2],lzy[N<<2];
    inline void pushdown(int o){
        sor[o<<1]=sor[o<<1|1]=sad[o<<1]=sad[o<<1|1]=lzy[o<<1]=lzy[o<<1|1]=lzy[o];
        lzy[o]=-1;
    }
    void fix(int o,int l,int r,int pos,int val){
        if(l==r){
            sor[o]+=val;
            sad[o]+=val;
            return;
        }
        if(lzy[o]!=-1) pushdown(o);
        int mid=l+r>>1;
        if(pos>mid) fix(o<<1|1,mid+1,r,pos,val);
        else fix(o<<1,l,mid,pos,val);
        sor[o]=sor[o<<1]|sor[o<<1|1];
        sad[o]=sad[o<<1]&sad[o<<1|1];
    }
    void updata(int o,int l,int r,int L,int R,int val){
        if(L<=l&&r<=R){
            sor[o]=sad[o]=lzy[o]=val;
            return;
        }
        if(lzy[o]!=-1) pushdown(o);
        int mid=l+r>>1;
        if(L>mid) updata(o<<1|1,mid+1,r,L,R,val);
        else if(R<=mid) updata(o<<1,l,mid,L,R,val);
        else {
            updata(o<<1,l,mid,L,R,val);
            updata(o<<1|1,mid+1,r,L,R,val);
        }
        sor[o]=sor[o<<1]|sor[o<<1|1];
        sad[o]=sad[o<<1]&sad[o<<1|1];
    }
    int find0(int o,int l,int r,int pos){
        if(!sor[o]) return -1;
        if(l==r) return l;
        if(lzy[o]!=-1) pushdown(o);
        int mid=l+r>>1;
        if(pos>mid) return find0(o<<1|1,mid+1,r,pos);
        else {
            int tmp=find0(o<<1,l,mid,pos);
            return tmp!=-1 ? tmp : find0(o<<1|1,mid+1,r,pos);
        }
    }
    int find1(int o,int l,int r,int pos){
        if(sad[o]==INF) return -1;
        if(l==r) return l;
        if(lzy[o]!=-1) pushdown(o);
        int mid=l+r>>1;
        if(pos>mid) return find1(o<<1|1,mid+1,r,pos);
        else {
            int tmp=find1(o<<1,l,mid,pos);
            return tmp!=-1 ? tmp : find1(o<<1|1,mid+1,r,pos);
        }
    }
    int query(int o,int l,int r,int pos){
        if(l==r) return sad[o];
        if(lzy[o]!=-1) pushdown(o);
        int mid=l+r>>1;
        if(pos>mid) return query(o<<1|1,mid+1,r,pos);
        else return query(o<<1,l,mid,pos);
    }
    inline void add(int pos,int x){
        int tmp=query(1,0,N,pos);
        if(tmp+x<=INF) fix(1,0,N,pos,x);
        else {
            fix(1,0,N,pos,x-INF-1);
            int ntp=find1(1,0,N,pos+1);
            if(ntp!=pos+1) updata(1,0,N,pos+1,ntp-1,0);
            fix(1,0,N,ntp,1);
        }
    }
    inline void del(int pos,int x){
        int tmp=query(1,0,N,pos);
        if(tmp-x>=0) fix(1,0,N,pos,-x);
        else {
            fix(1,0,N,pos,INF+1-x);
            int ntp=find0(1,0,N,pos+1);
            if(ntp!=pos+1) updata(1,0,N,pos+1,ntp-1,INF);
            fix(1,0,N,ntp,-1);
        }
    }
    int main(){
        scanf("%d",&n); int t1,t2,t3; scanf("%d %d %d",&t1,&t2,&t3);
        while(n--){
            int opt; scanf("%d",&opt);
            if(opt==1){
                int a,b,pos; scanf("%d %d",&a,&b); pos=b/30;
                if(a==0) continue;
                if(a>0){
                    add(pos,(a<<(b-pos*30))&INF);
                    add(pos+1,a>>(30-(b-pos*30)));
                } else {
                    a=-a;
                    del(pos,(a<<(b-pos*30))&INF);
                    del(pos+1,a>>(30-(b-pos*30)));
                }
            } else {
                int k,pos; scanf("%d",&k); pos=k/30;
                printf("%c
    ",(query(1,0,N,pos)&(1<<(k-pos*30)) ? 1 : 0)^'0');
            }
        }
        return 0;
    }
    
  • 相关阅读:
    让你的网站(MAXCMS4_0)按地区、年份、语言生成分页面(已经修正)
    IPTV
    超简单,MAX普通版改为资源版方法
    Jmter操作数据库
    JMter中添加断点和关联
    jmeter返回报文乱码问题
    Jmter安装和配置
    JMter压力测试
    今天注册了
    不能登陆后删除Cookies解决
  • 原文地址:https://www.cnblogs.com/PotremZ/p/NOI2017D1T1.html
Copyright © 2020-2023  润新知