• luogu3822 [NOI2017]整数


    [NOI2017]整数

    最简单的想法是模拟这个过程,即对于(a)将其拆成许多个(2^i)之和,然后将每一个暴力的往那个高精度二进制数上加或减,对于加法,我们在这一位上加1,如果这一位原来是1的话下我们就将高位上连续的一段1变成0,并且将再下一位的0变成1(模拟一下这个进位过程)。减法的话同理,就是把上文的01互换了

    这样的话时间复杂度是(O(nlog^2n)),会被卡

    很显然的事情是每一位上只有(0,1)太浪费了,我们可以考虑将连续的(30)个二进制位压在一起,这样的话在不考虑进位时至多只需要对两位进行修改,考虑进位的话也只需要考虑高位上的连续的(0)(2^{30}-1)即可

    时间被优化到了(O(nlogn))可以通过,查询区间是否是连续的(0)或者(2^{30}-1)可以通过线段树维护区间(or/and)和来查询

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    const int N=1000010,M=(1<<30)-1,B=30;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 998244353
    #define eps 1e-8
    struct node{
        int suma,sumo;
    }seg[4004000];
    int n,tag[4004000];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    void pushup(int id)
    {
        //cout <<seg[id<<1].sumo << " " << seg[id<<1].suma << " " << seg[id<<1|1].sumo << " " << seg[id<<1|1].suma << endl;
        seg[id].sumo=(seg[id<<1].sumo|seg[id<<1|1].sumo);
        seg[id].suma=(seg[id<<1].suma&seg[id<<1|1].suma);
    }
    
    void pushdown(int id)
    {
        if (tag[id]!=-1)
        {
            seg[id<<1].sumo=seg[id<<1].suma=tag[id<<1]=seg[id<<1|1].sumo=seg[id<<1|1].suma=tag[id<<1|1]=tag[id];
            tag[id]=-1;
        }
    }
    
    int find0(int id,int l,int r,int pos)
    {
        if (seg[id].suma==M) return -1;
        if (l==r) return l;pushdown(id);
        int mid=(l+r)>>1,ans=-1;
        if (pos<=mid) ans=find0(id<<1,l,mid,pos);
        if (ans!=-1) return ans;
        else return find0(id<<1|1,mid+1,r,pos);
    }
    
    int find1(int id,int l,int r,int pos)
    {
        if (seg[id].sumo==0) return -1;
        if (l==r) return l;pushdown(id);
        int mid=(l+r)>>1,ans=-1;
        if (pos<=mid) ans=find1(id<<1,l,mid,pos);
        if (ans!=-1) return ans;
        else return find1(id<<1|1,mid+1,r,pos);
    }
    
    void modify(int id,int l,int r,int ql,int qr,int val)
    {
        //cout << id << " "<< l << " " << r << " " << ql << " " << qr << endl;
        if ((l>=ql) && (r<=qr)) 
        {
            seg[id].sumo=val;seg[id].suma=val;tag[id]=val;
            return;
        }
        int mid=(l+r)>>1;pushdown(id);
        if (ql<=mid) modify(id<<1,l,mid,ql,qr,val);
        if (qr>mid) modify(id<<1|1,mid+1,r,ql,qr,val);
        pushup(id);
    }
    
    void update(int id,int l,int r,int pos,int val)
    {
        //cout << l << " " << r << " "  << pos << " " << seg[id].suma << endl;
        if (l==r) {seg[id].sumo+=val;seg[id].suma+=val;return;}
        int mid=(l+r)>>1;pushdown(id);
        if (pos<=mid) update(id<<1,l,mid,pos,val);
        else update(id<<1|1,mid+1,r,pos,val);
        pushup(id);
    }
    
    int query(int id,int l,int r,int pos)
    {
        if (l==r) return seg[id].sumo;
        int mid=(l+r)>>1;pushdown(id);
        if (pos<=mid) return query(id<<1,l,mid,pos);
        else return query(id<<1|1,mid+1,r,pos);
    }
    
    void inc(int pos,int val)
    {
        int now=query(1,0,N,pos);
        if (now+val<=M) update(1,0,N,pos,val);
        else
        {
            update(1,0,N,pos,val-(M+1));
            int nxt=find0(1,0,N,pos+1);
            if (nxt>pos+1) modify(1,0,N,pos+1,nxt-1,0);
            update(1,0,N,nxt,1);
        }
    }
    
    void dec(int pos,int val)
    {
        int now=query(1,0,N,pos);
        if (now>=val) update(1,0,N,pos,-val);
        else
        {
            update(1,0,N,pos,(M+1)-val);
            int nxt=find1(1,0,N,pos+1);
            if (nxt>pos+1) modify(1,0,N,pos+1,nxt-1,M);
            update(1,0,N,nxt,-1);
        }
    }
    
    void build(int id,int l,int r)
    {
        tag[id]=-1;
        if (l==r) return;
        int mid=(l+r)>>1;
        build(id<<1,l,mid);build(id<<1|1,mid+1,r);
    }
    
    int main()
    {
        //freopen("a.out","w",stdout);
        n=read();read();read();read();
        build(1,0,N);
        rep(i,1,n)
        {
            int op=read();
            if (op==1)
            {
                int a=read(),b=read(),wei=b/B;
                if (a>0)
                {
                    inc(wei,(a<<(b-wei*B))&M);
                    inc(wei+1,(a>>((wei+1)*B-b)));
                }
                else
                {
                    a=-a;
                    dec(wei,(a<<(b-wei*B))&M);
                    dec(wei+1,(a>>((wei+1)*B-b)));
                }
            }
            else if (op==2)
            {
                int x=read(),wei=x/B;
                int ans=query(1,0,N,wei);
                int rst=x-wei*B;
                printf("%d
    ",(ans>>rst)&1);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    一个很大的数(计数、思维)
    第3章 图嵌入
    第一章 绪论
    区间最大值(数论分块)
    爬塔(set、括号匹配)
    第2章 图论基础
    V字钩爪(贪心)
    金牌厨师(二分、差分)
    Coprime(埃氏筛)
    Reordering(组合计数)
  • 原文地址:https://www.cnblogs.com/encodetalker/p/11141331.html
Copyright © 2020-2023  润新知