[NOI2017]整数

Description
  P 博士将他的计算任务抽象为对一个整数的操作。
  具体来说,有一个整数 x x ,一开始为0
  接下来有 n n 个操作,每个操作都是以下两种类型中的一种:

  1 a a b :将 x x 加上整数 a2b ,其中 a a 为一个整数,b 为一个非负整数
   2 2 k :询问 x x 在用二进制表示时,位权为 2k 的位的值(即这一位上的 1 1 代表 2k

  保证在任何时候, x0 x ≥ 0 。( n106 n ≤ 10 6 a109 a ≤ 10 9 b,k30n b , k ≤ 30 n

Input
  输入的第一行包含四个正整数 n,t1,t2,t3 n , t 1 , t 2 , t 3 n n 的含义见题目描述,t1,t2,t3 的具体含义见子任务。
  接下来 n n 行,每行给出一个操作,具体格式和含义见题目描述。

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

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

Solution
  首先很显然有log2n的做法,然而每次修改一位太浪费了,于是我们考虑每 30 30 位压一下,发现二进制下我们每次进位最多是 1 1 ,借位最多也是1,于是每次我们要进位借位的时候就往前面找第一个合法的位置,操作一下即可。
  这样的话每次修改最多涉及到两个数,分别处理。询问直接查询即可。
  效率 O(nlogn) O ( n l o g n )

Source

//2018-4-21
//miaomiao
//
#include <bits/stdc++.h>
using namespace std;

#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define N (1000000 + 5)

int XOP;
char chr;
inline void Read(int &x){
    chr = getchar(); XOP = 0;
    while(chr < '0' || chr > '9'){
        if(chr == '-') XOP = 1; chr = getchar();
    }

    x = 0;
    while(chr >= '0' && chr <= '9'){
        x = (x << 1) + (x << 3) + (chr ^ '0');
        chr = getchar();
    }
    if(XOP) x = -x;
}

const int MX = (1 << 30) - 1;
int n, m, T1, T2, T3, qr;

namespace SegTree{
    int h1[N << 2], h2[N << 2], tnum[N << 2]; // h1 is or || h2 is and
    bool tag[N << 2];

#define lc (o << 1)
#define rc (o << 1 | 1)
#define mid ((L + R) >> 1)

    void Pushup(int o){
        h1[o] = h1[lc] | h1[rc]; h2[o] = h2[lc] & h2[rc];
    }

    void Pushdown(int o){
        if(!tag[o]) return;

        tag[lc] = tag[rc] = true; tag[o] = false;
        h1[lc] = h2[lc] = h1[rc] = h2[rc] = tnum[lc] = tnum[rc] = tnum[o];
    }

    void Tag(int o, int L, int R, int ql, int qr, int av){
        if(ql <= L && qr >= R){
            h1[o] = h2[o] = tnum[o] = av; tag[o] = true; return;
        }

        Pushdown(o);
        if(ql <= mid) Tag(lc, L, mid, ql, qr, av);
        if(qr > mid) Tag(rc, mid + 1, R, ql, qr, av);
        Pushup(o);
    }

    bool Find(int o, int L, int R, int ql, int op){
        if(!h1[o] && op == -1) return false;
        if(h2[o] == MX && op == 1) return false;

        if(L == R){
            h1[o] = h2[o] = h1[o] + op; qr = L - 1;
            return true;
        }

        Pushdown(o);
        int ret = 0;
        if(ql <= mid) ret |= Find(lc, L, mid, ql, op);
        if(!ret) ret |= Find(rc, mid + 1, R, ql, op);
        Pushup(o);

        return ret;
    }

    void Modify(int o, int L, int R, int p, int ad, int op){
        if(L == R){
            h1[o] = h2[o] = h1[o] + ad * op;
            if(h1[o] >= 0 && h1[o] <= MX) return;

            if(h1[o] > MX) h1[o] = h2[o] = h1[o] - (MX + 1);
            if(h1[o] < 0) h1[o] = h2[o] = h1[o] + (MX + 1);


            Find(1, 1, n, L + 1, op);
            if(L < qr) Tag(1, 1, n, L + 1, qr, op == 1? 0: MX);
            return;
        }

        Pushdown(o);
        if(p <= mid) Modify(lc, L, mid, p, ad, op);
        else Modify(rc, mid + 1, R, p, ad, op);
        Pushup(o);
    }

    void Query(int o, int L, int R, int p, int pw){
        if(L == R){
            printf("%c\n", (h1[o] & (1 << pw))? '1': '0');
            return;
        }

        Pushdown(o);
        if(p <= mid) Query(lc, L, mid, p, pw);
        else Query(rc, mid + 1, R, p, pw);
        Pushup(o);
    }

#undef lc
#undef rc
#undef mid
};

void Update(int pos, int av, int op){
    SegTree::Modify(1, 1, n, pos, av, op);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("4.in", "r", stdin);
    freopen("int.out", "w", stdout);
#endif

    n = 1000002;

    int op, a, b, t1, t2, opa;
    Read(m), Read(T1), Read(T2), Read(T3);

    while(m --){
        Read(op);

        if(op == 1){
            Read(a), Read(b);
            opa = a < 0? -1: 1; a = abs(a);

            t1 = b / 30 + 1; t2 = 30 - b % 30;

            if(b % 30 == 0) Update(t1, a, opa);
            else{
                int y = a >> t2, x = (a - (y << t2)) << (30 - t2);
                Update(t1, x, opa); Update(t1 + 1, y, opa);
            }
        }else{
            Read(b);
            t1 = b / 30 + 1; t2 = b % 30;
            SegTree::Query(1, 1, n, t1, t2);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值