zoukankan      html  css  js  c++  java
  • NOI 2017 整数

    好玄学的线段树啊...

    调了半天的题,最后发现是传参的数据类型传错了(long long 传成了int),结果RE3小时...

    说下思路吧...

    其实主题思想很简单,就是把一个二进制数作为一个序列建立一棵线段树,然后各种维护即可

    当然这样会TLE或MLE之类的

    所以我们采用其他的策略:压位!!!

    这里我选择压60位。

    然后我们考虑:对一次修改操作,我们如何处理?

    首先,我们看一下这个操作会被分在哪一组里。

    很显然,如果这一次操作为a·2^b,那么一定会被分在第b/60组里!(或者至少有一部分在第b/60组里)!

    那么就好办了,我们把会被分在这一组里的部分加到这一组里即可

    那么谁是会被分到这一组里的部分呢?

    自然是(a·2^(b mod 60))mod (2^60-1)这些了!

    等等,那剩下的部分怎么办?

    换句话说,我们只是把可能在这部分里的值加了进去,那万一a特别大,一部分值超越了分到的部分呢?

    对于这一部分,根据数据范围,我们可以确定的是,我们压60位以后,一个幂次已经被取模后的修改不会跨越两个相邻块!

    那我们就把剩余部分放到下一块就好了

    减法也就是同理啦

    所以我们的操作长这样:

    ll typ=read();
            if(typ==1)
            {
                ll a=read(),b=read();
                int p1=b/seed,p2=b%seed;
                if(a>0)
                {
                    ll x=(a<<p2)&INF;
                    if(x)
                    {
                        add(p1,x);
                    }
                    p1++;
                    a>>=(seed-p2);
                    if(b)
                    {
                        add(p1,a);
                    }
                }else
                {
                    a=-a;
                    ll x=(a<<p2)&INF;
                    if(x)
                    {
                        sub(p1,x);
                    }
                    p1++;
                    a>>=(seed-p2);
                    if(b)
                    {
                        sub(p1,a);
                    }
                }
            }

    接下来就是最复杂的部分了:如何进行修改?

    这就涉及到线段树的维护了。

    对于每个节点,我们存储以下几个信息:

    第一:这个节点是否是全1

    第二:这个节点是否是全0

    第三:表示这个节点性质的lazy标签

    然后我们进行维护:

    首先我们假设进行的是加法,那么我们首先要在这个块里进行修改,修改很简单,就是对这个块加上你扔进来的值即可。

    可是,这样会产生几个问题:

    第一:如果加爆了怎么办?

    显然涉及到进位问题啊。

    这个问题我们稍后再解决。

    第二:怎么进行单点修改?

    把单点修改转成区间修改,然后修改一条树链即可。

    第三:怎么知道你要修改的点的值?

    我们维护一个data数组存储,查询时在线段树上查询即可

    单点修改:

    void change(int rt,ll val)
    {
        if(posi[rt]!=-1)
        {
            data[posi[rt]]=val;
        }
        if(val==0)
        {
            tree[rt].tag[0]=1;
            tree[rt].tag[1]=0;
            tree[rt].lazy=0;
        }else if(val==INF)
        {
            tree[rt].tag[0]=0;
            tree[rt].tag[1]=1;
            tree[rt].lazy=INF;
        }else
        {
            tree[rt].tag[0]=tree[rt].tag[1]=0;
            tree[rt].lazy=-1;
        }
    }

    区间操作:

    void ins_range(int rt,int l,int r,ll val)
    {
        if(ls>=l&&rs<=r)
        {
            change(rt,val);
            return;
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        if(mid>=l)
        {
            ins_range(rt1,l,r,val);
        }
        if(mid<r)
        {
            ins_range(rt2,l,r,val);
        }
        pushup(rt);
    }

    上传和下传:

    void pushdown(int rt)
    {
        if(tree[rt].lazy!=-1)
        {
            change(rt1,tree[rt].lazy);
            change(rt2,tree[rt].lazy);
            tree[rt].lazy=-1;
        }
    }
    void pushup(int rt)
    {
        tree[rt].tag[0]=(tree[rt1].tag[0]&tree[rt2].tag[0]);
        tree[rt].tag[1]=(tree[rt1].tag[1]&tree[rt2].tag[1]);
    }

    查询某一点:

    ll query(int rt,int posii)
    {
        if(ls==rs)
        {
            return data[ls];
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        if(posii<=mid)
        {
            return query(rt1,posii);
        }else
        {
            return query(rt2,posii);
        }
    }

    接下来我们讨论加爆了的情况

    如果加爆了,向前进位也只会进1位,那我们再对前面第一个不全为1的块去+1即可

    等等,怎么找到这种块?

    利用上面的标记,进行查找即可。

    查找操作:

    int findf(int rt,int posii,int typ)
    {
        if(typ==1&&tree[rt].tag[0])
        {
            return -1;
        }else if(typ==0&&tree[rt].tag[1])
        {
            return -1;
        }
        if(ls==rs)
        {
            return ls;
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        int t;
        if(posii<=mid)
        {
            t=findf(rt1,posii,typ);
            if(t!=-1)
            {
                return t; 
            }
        }
        return findf(rt2,posii,typ);
    }

    最后加减法就是聊尽人事了:

    void add(int posii,ll val)
    {
        ll temp=query(1,posii);
        ins_range(1,posii,posii,(temp+val)&INF);
        if(temp+val>INF)
        {
            int pos=findf(1,posii+1,0);
            ins_range(1,pos,pos,data[pos]+1);
            if(pos-1>=posii+1)
            {
                ins_range(1,posii+1,pos-1,0);
            }
        }
    }
    void sub(int posii,ll val)
    {
        ll temp=query(1,posii);
        ins_range(1,posii,posii,(temp-val)&INF);
        if(temp-val<0)
        {
            int pos=findf(1,posii+1,1);
            ins_range(1,pos,pos,data[pos]-1);
            if(pos-1>=posii+1)
            {
                ins_range(1,posii+1,pos-1,INF);
            }
        }
    }

    最后,全代码:

    
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ls tree[rt].lson
    #define rs tree[rt].rson
    #define rt1 rt<<1
    #define rt2 (rt<<1)|1
    #define ll long long
    using namespace std;
    const ll seed=60;
    const ll INF=(1ll<<60)-1;
    struct Tree
    {
        int lson;
        int rson;
        int tag[2];
        ll lazy;
    }tree[2000005];
    int posi[2000005];
    ll data[2000005];
    void buildtree(int rt,int l,int r)
    {
        tree[rt].lson=l;
        tree[rt].rson=r;
        tree[rt].tag[0]=1;
        tree[rt].lazy=-1;
        posi[rt]=-1;
        if(l==r)
        {
            posi[rt]=l;
            return;
        }
        int mid=(l+r)>>1;
        buildtree(rt1,l,mid);
        buildtree(rt2,mid+1,r);
    }
    void change(int rt,ll val)
    {
        if(posi[rt]!=-1)
        {
            data[posi[rt]]=val;
        }
        if(val==0)
        {
            tree[rt].tag[0]=1;
            tree[rt].tag[1]=0;
            tree[rt].lazy=0;
        }else if(val==INF)
        {
            tree[rt].tag[0]=0;
            tree[rt].tag[1]=1;
            tree[rt].lazy=INF;
        }else
        {
            tree[rt].tag[0]=tree[rt].tag[1]=0;
            tree[rt].lazy=-1;
        }
    }
    void pushdown(int rt)
    {
        if(tree[rt].lazy!=-1)
        {
            change(rt1,tree[rt].lazy);
            change(rt2,tree[rt].lazy);
            tree[rt].lazy=-1;
        }
    }
    void pushup(int rt)
    {
        tree[rt].tag[0]=(tree[rt1].tag[0]&tree[rt2].tag[0]);
        tree[rt].tag[1]=(tree[rt1].tag[1]&tree[rt2].tag[1]);
    }
    void ins_range(int rt,int l,int r,ll val)
    {
        if(ls>=l&&rs<=r)
        {
            change(rt,val);
            return;
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        if(mid>=l)
        {
            ins_range(rt1,l,r,val);
        }
        if(mid<r)
        {
            ins_range(rt2,l,r,val);
        }
        pushup(rt);
    }
    ll query(int rt,int posii)
    {
        if(ls==rs)
        {
            return data[ls];
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        if(posii<=mid)
        {
            return query(rt1,posii);
        }else
        {
            return query(rt2,posii);
        }
    }
    int findf(int rt,int posii,int typ)
    {
        if(typ==1&&tree[rt].tag[0])
        {
            return -1;
        }else if(typ==0&&tree[rt].tag[1])
        {
            return -1;
        }
        if(ls==rs)
        {
            return ls;
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        int t;
        if(posii<=mid)
        {
            t=findf(rt1,posii,typ);
            if(t!=-1)
            {
                return t; 
            }
        }
        return findf(rt2,posii,typ);
    }
    void add(int posii,ll val)
    {
        ll temp=query(1,posii);
        ins_range(1,posii,posii,(temp+val)&INF);
        if(temp+val>INF)
        {
            int pos=findf(1,posii+1,0);
            ins_range(1,pos,pos,data[pos]+1);
            if(pos-1>=posii+1)
            {
                ins_range(1,posii+1,pos-1,0);
            }
        }
    }
    void sub(int posii,ll val)
    {
        ll temp=query(1,posii);
        ins_range(1,posii,posii,(temp-val)&INF);
        if(temp-val<0)
        {
            int pos=findf(1,posii+1,1);
            ins_range(1,pos,pos,data[pos]-1);
            if(pos-1>=posii+1)
            {
                ins_range(1,posii+1,pos-1,INF);
            }
        }
    }
    inline ll read()
    {
        ll f=1,x=0;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;
    }
    int n,whatever1,whatever2,whatever3;
    int main()
    {
        n=read(),whatever3=read(),whatever2=read(),whatever1=read();
        buildtree(1,0,n/2+2);
        while(n--)
        {
            ll typ=read();
            if(typ==1)
            {
                ll a=read(),b=read();
                int p1=b/seed,p2=b%seed;
                if(a>0)
                {
                    ll x=(a<<p2)&INF;
                    if(x)
                    {
                        add(p1,x);
                    }
                    p1++;
                    a>>=(seed-p2);
                    if(b)
                    {
                        add(p1,a);
                    }
                }else
                {
                    a=-a;
                    ll x=(a<<p2)&INF;
                    if(x)
                    {
                        sub(p1,x);
                    }
                    p1++;
                    a>>=(seed-p2);
                    if(b)
                    {
                        sub(p1,a);
                    }
                }
            }else
            {
                ll q=read();
                printf("%lld
    ",(query(1,q/seed)>>(q%seed))&1);
            }
        }
    }
  • 相关阅读:
    【转载】Python tips: 什么是*args和**kwargs?
    Python关于File学习过程
    tensorflow训练中出现nan
    axis调用Web服务报axis unexpected wrapper element{XXXX}XXX错误的解决
    微信小程序windowHeight的值在ios和android平台不一致问题解决办法
    微信小程序scroll-view滚动一次多次触发的问题解决方案
    微信小程序自定义TabBar
    微信小程序页面列表与详情页跳转的正确姿势
    Spring动态获取已注入的对象的方法
    MAVEN项目不扫描mybatis的mapper.xml问题
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764222.html
Copyright © 2011-2022 走看看