被陈指导秒掉的一眼题,然而我需要接受陈指导的指导才会做
首先根据经典的势能分析,直接暴力做加法复杂度其实是对的,每一位的贡献是(O(1))级别的
而且这里的(30n)的数据范围也印证了这一点,我们直接暴力压位即可
但是这种做法显然不支持撤销,因此减法的时候就会直接GG
我们考虑分别维护出加上的数的和以及减去的数的和
考虑求第(k)位,容易发现我们此时只要判断([0,k))位会不会出现借位即可
显然我们只需要找到小于(k)的第一个不相同的位置即可,用set
维护所有不相同的位置即可实现
复杂度(O(30n+nlog n))
#include<cstdio>
#include<set>
#include<cctype>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define int long long
using namespace std;
typedef set <int>:: iterator SI;
const int N=1000005,S=(1LL<<32)-1;
int n,opt,x,y,a[N],b[N]; set <int> s;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() ((A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin)),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; int flag=1; while (!isdigit(ch=tc())) if (ch=='-') flag=-1;
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); x*=flag;
}
#undef tc
}F;
inline void reset(int *a,int *b,CI p)
{
if (a[p]!=b[p]) { if (!s.count(p)) s.insert(p); }
else { if (s.count(p)) s.erase(p); }
}
inline void add(int *a,int *b,CI x,CI y)
{
int p=y>>5,q=y&31; a[p]+=(1LL<<q)*x; a[p+1]+=(a[p]>>32); a[p]&=S; reset(a,b,p); ++p;
while (a[p]>S) a[p+1]+=(a[p]>>32),a[p]&=S,reset(a,b,p),++p; reset(a,b,p);
}
inline int query(CI x)
{
int p=x>>5,q=x&31,tp=((a[p]>>q)^(b[p]>>q))&1;
int la=a[p]&((1LL<<q)-1),lb=b[p]&((1LL<<q)-1);
if (la!=lb) return tp^(la<lb); SI pos=s.lower_bound(p);
if (pos==s.begin()) return tp; return --pos,tp^(a[*pos]<b[*pos]);
}
signed main()
{
for (F.read(n),F.read(x),F.read(x),F.read(x);n;--n)
{
F.read(opt); F.read(x); if (opt==1)
{ if ( F.read(y),x>0) add(a,b,x,y); else add(b,a,-x,y); }
else putchar(query(x)?'1':'0'),putchar('
');
}
return 0;
}