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('\n')
#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\n",query(1,0,n,k));
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/thkkk/p/7647740.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值