Description
P 博士将他的计算任务抽象为对一个整数的操作。
具体来说,有一个整数
x
x
,一开始为。
接下来有
n
n
个操作,每个操作都是以下两种类型中的一种:
a
a
:将
x
x
加上整数 ,其中
a
a
为一个整数, 为一个非负整数
2
2
:询问
x
x
在用二进制表示时,位权为 的位的值(即这一位上的
1
1
代表 )
保证在任何时候, x≥0 x ≥ 0 。( n≤106 n ≤ 10 6 , a≤109 a ≤ 10 9 , b,k≤30n b , k ≤ 30 n )
Input
输入的第一行包含四个正整数
n,t1,t2,t3
n
,
t
1
,
t
2
,
t
3
,
n
n
的含义见题目描述, 的具体含义见子任务。
接下来
n
n
行,每行给出一个操作,具体格式和含义见题目描述。
同一行输入的相邻两个元素之间,用恰好一个空格隔开。
Output
对于每个询问操作,输出一行,表示该询问的答案(或
1
1
)。 对于加法操作,没有任何输出。
Solution
首先很显然有的做法,然而每次修改一位太浪费了,于是我们考虑每
30
30
位压一下,发现二进制下我们每次进位最多是
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;
}