NOI2017 整数(线段树)

「NOI2017」整数

问题描述

在人类智慧的山巅,有着一台字长为 $1048576$ 位的超级计算机,著名理论计算机科学家 P 博士正用它进行各种研究。
不幸的是,这天台风切断了电力系统,超级计算机无法工作,而 P 博士明天就要交实验结果了,只好求助于学过 OI 的你……

P 博士将他的计算任务抽象为对一个整数的操作。

具体来说,有一个整数 $x$ ,一开始为 $0$。

接下来有 $n$ 个操作,每个操作都是以下两种类型中的一种:

  • 1 $a$ $b$ :将 $x$ 加上整数 $a \cdot 2 ^ b$,其中 $a$ 为一个整数,$b$ 为一个非负整数

  • 2 $k$ :询问 $x$ 在用二进制表示时,位权为 $2 ^ k$ 的位的值(即这一位上的 $1$ 代表 $2 ^ k$ )

保证在任何时候,$x \ge 0$。

输入格式

从标准输入读入数据。

输入的第一行包含四个正整数 $n, t_1, t_2, t_3$,$n$ 的含义见题目描述,$t_1, t_2, t_3$ 的具体含义见子任务。

接下来 $n$ 行,每行给出一个操作,具体格式和含义见题目描述。

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

输出格式

输出到标准输出。

对于每个询问操作,输出一行,表示该询问的答案($0$ 或 $1$)。

对于加法操作,没有任何输出。

样例输入

10 3 1 2
1 100 0
1 2333 0
1 -233 0
2 5
2 7
2 15
1 5 15
2 15
1 -1 12
2 15

样例输出

0
1
0
1
0

提示

子任务

在所有测试点中,$1 \le t_1 \le 3, 1 \le t_2 \le 4, 1 \le t_3 \le 2$。
不同的 $t_1, t_2, t_3$ 对应的特殊限制如下:

  • 对于 $t_1 = 1$ 的测试点,满足 $a = 1$

  • 对于 $t_1 = 2$ 的测试点,满足 $|a| = 1$

  • 对于 $t_1 = 3$ 的测试点,满足 $|a| \le 10 ^ 9$

  • 对于 $t_2 = 1$ 的测试点,满足 $0 \le b,k \le 30$

  • 对于 $t_2 = 2$ 的测试点,满足 $0 \le b,k \le 100$

  • 对于 $t_2 = 3$ 的测试点,满足 $0 \le b,k \le n$

  • 对于 $t_2 = 4$ 的测试点,满足 $0 \le b,k \le 30 n$

  • 对于 $t_3 = 1$ 的测试点,保证所有询问操作都在所有修改操作之后

  • 对于 $t_3 = 2$ 的测试点,不保证询问操作和修改操作的先后顺序

本题共 25 个测试点,每个测试点 4 分。各个测试点的数据范围如下:


测试点编号 $n \le$ $t_1$ $t_2$ $t_3$
$1$ $10$ $3$ $1$ $2$
$2$ $100$ $2$
$3$ $2000$
$4$ $4000$ $1$ $3$
$5$ $6000$ $3$ $1$
$6$ $8000$ $2$ $2$
$7$ $9000$ $3$ $4$
$8$ $10000$ $3$
$9$ $30000$ $4$
$10$ $50000$ $1$
$11$ $60000$ $3$ $2$
$12$ $65000$ $2$ $4$
$13$ $70000$ $3$
$14$ $200000$
$15$ $300000$ $2$
$16$ $400000$ $3$
$17$ $500000$ $3$
$18$ $600000$ $4$
$19$ $700000$
$20$ $800000$ $1$
$21$ $900000$ $2$
$22$ $930000$ $3$ $3$
$23$ $960000$ $4$ $1$
$24$ $990000$ $3$ $2$
$25$ $1000000$ $4$

首先容易想到如果只有加法,那么可以暴力的维护每个二进制位模拟进位,根据势能分析$(?)$可知,复杂度是均摊$O(1)$的。

考虑减法,由于保证了任意时刻结果非负,那么可以将加和减分开存成两个数$s1$和$s2$,这样就只用做加法了。然后判断答案的时候由于非负,那么$x$位更高的部分是不用管的,只考虑$0-x$位即可。

然后发现只需要比较$[0,x-1]$位的大小就行了。如果$s1>s2$,那么答案就是$s1[x]\ xor\ s2[x]$,否则答案就是$s1[x]==s2[x]$,这个用线段树维护一下$s1[i]\ xor\ s2[i]$的值就能解决了。

复杂度$O(n\log N)$需要优秀的常数才能通过。


代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<bitset>
using namespace std;
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?0:*p1++)
inline void _R(int &x)
{
char t=GC;bool f=0;
while(t!='-'&&(t<48||t>57))t=GC;
if(t=='-')f=1,t=GC;
for(x=0;t>47&&t<58;t=GC)x=(x<<3)+(x<<1)+t-48;
x=f?-x:x;
}
const int N=1<<25;
int n,t1,t2,t3,a,b,L,R;
bitset<N>s1,s2;
bitset<N<<1>v;
void CHA()
{
if(!a)return;
int w=a>0?a:-a,t[32],i,cnt=0,p;
for(i=0;i<31;i++)if(w>>i&1)t[++cnt]=i;
L=b+t[1];R=b+t[cnt];
if(a>0)
{
for(i=1;i<=cnt;i++)
{
p=t[i]+b;
while(s1[p])s1[p++]=0,R=max(R,p);
s1[p]=1;
}
}
else
{
for(i=1;i<=cnt;i++)
{
p=t[i]+b;
while(s2[p])s2[p++]=0,R=max(R,p);
s2[p]=1;
}
}
}
void MD()
{
for(int i=L;i<=R;i++)v[i+N]=s1[i]^s2[i];
for(L=(L+N)>>1,R=(R+N)>>1;L;L>>=1,R>>=1)
for(int i=L;i<=R;i++)v[i]=v[i<<1]|v[i<<1|1];
}
int find(int k)
{
for(k+=N;k;k>>=1)
if(k&1&v[k^1])
{
for(k^=1;k<N;k=k<<1|v[k<<1|1]);
return k-N;
}
return -1;
}
int main()
{
int i,j,k,x,y;
_R(n);_R(t1);_R(t2);_R(t3);
for(i=1;i<=n;i++)
{
_R(k);
if(k==1)_R(a),_R(b),CHA(),MD();
else
{
_R(a);x=find(a);
if(x==-1||s1[x]>s2[x])printf("%d\n",s1[a]^s2[a]);
else printf("%d\n",s1[a]==s2[a]);
}
}
}