减法产生退位,这个十分不好处理,考虑把加的数和减的数分别存在$a,b$
修改就直接把对应位置往后$30$位提出来,做加法,再回去更新,如果产生了进位($31$位),那么暴力更新即可,反正进位次数是均摊$O(1)$
查询时等于是判断$a-b$在第$k$位的值,我们需要知道第$k$位在做减法时是否产生退位,那么只需要比较$a$和$b$的前$k-1$位的大小即可,我们需要找到$a,b$的$k$位以下第一个不等的位,这一步直接用线段树维护$a\text{ xor }b$即可,查询时在线段树上跑就可以了
空间和时间应该都很爆炸,但是能过...
#includebool x[2][30000100],s[67108864];int M;void pushup(int x){s[x]=s[x<<1]|s[x<<1|1];}void modify(int x){ s[x+=M]^=1; while(x>>=1)pushup(x);}int down(int x){ return x>=M?x-M:(s[x<<1|1]?down(x<<1|1):down(x<<1));}int up(int x){ return x==1?-1:((x&1)&&s[x^1]?down(x^1):up(x>>1));}void add(int a,int b){ int i,f,t,tt; f=0; if(a<0){ a=-a; f=1; } t=0; for(i=b+29;i>=b;i--)t=t*2+x[f][i]; tt=t+a; for(i=b;i<=b+29;i++){ x[f][i]=tt>>(i-b)&1; if((tt>>(i-b)&1)^(t>>(i-b)&1))modify(i); } if(tt>=1<<30){ for(i=b+30;x[f][i];i++){ x[f][i]=0; modify(i); } x[f][i]=1; modify(i); }}int query(int k){ int s,i; s=x[0][k]^x[1][k]; i=up(k+M); if(i!=-1&&x[0][i]