https://www.luogu.org/problemnew/show/P3822
题解
如果只有加法没有减法,那么我们朴素进位的时间复杂度是均摊(O(1))的。
那么减法的话我们维护一个增量的数,一个减量的数,就是一个存所有(a>0)的变量,一个存所有(a<0)的变量。
那么我们考虑一个位置的数是(0)还是(1),我们先对这个位置做个减法,然后唯一对这个值有影响的就是低位是否有借位,如果有,这一位就翻转。
那么问题就转化为比较两个数的大小,用set维护不一样的位置就行了。
然后这道题的范围是(30n),所以我们可以把每(30)个位压成一个(int)存就可以了,每次只会对两个位置进行修改。
注意,提取一个负数的某个二进制位的时候可能会出问题,最好把它搞成正的再去做。
代码
#include <bits/stdc++.h>
#define N 1000002
using namespace std;
typedef long long ll;
typedef unsigned int u;
int maxn=1000000;
int n,t1,t2,t3;
u z[N],f[N];
bool cun[N];
set<int>s;
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline void work(int x){
if(z[x]==f[x]){
s.erase(x);
}
else s.insert(x);
}
int main(){
n=rd();
t1=rd();t2=rd();t3=rd();
int opt;
int a,b;////
u maxx=(1u<<30)-1;
while(n--){
opt=rd();
if(opt==1){
a=rd();b=rd();
int wei=maxn-int(b/30);
int _wei=b%30;
int tg=0;
if(a<0)tg=1,a=-a;/////
for(int j=0;j<30;++j){
cun[j]=(a&(1u<<j))!=0;
}
if(tg)a=-a;
int now=30-_wei;//
u num=0;
for(int j=0;j<now;++j){
num+=(1u<<j)*cun[j];
}
if(a>0){
num<<=_wei;
z[wei]=(num+z[wei]);
num=0;
if(z[wei]>maxx)
z[wei]=z[wei]&maxx,num=1;
for(int j=now;j<30;++j){
num+=cun[j]*(1u<<j-now);
}
--wei;
z[wei]+=num;
while(wei>0&&z[wei]>maxx){
z[wei]&=maxx;
z[wei-1]++;
wei--;
}
}
else{
num<<=_wei;
f[wei]=(num+f[wei]);
num=0;
if(f[wei]>maxx)
f[wei]=f[wei]&maxx,num=1;
for(int j=now;j<30;++j){
num+=cun[j]*(1u<<j-now);
}
--wei;
f[wei]+=num;
while(wei>0&&f[wei]>maxx){
f[wei]&=maxx;
f[wei-1]++;
wei--;
}
}
int chu=maxn-int(b/30);
for(int j=wei;j<=chu;++j)work(j);
}
else{
b=rd();
int wei=maxn-int(b/30);
int _wei=b%30;
int ans=(((z[wei]&(1<<_wei))!=0)-((f[wei]&(1<<_wei))!=0)+2)%2;
bool tag=0;
for(int j=_wei-1;j>=0;--j)
if((z[wei]&(1<<j))!=(f[wei]&(1<<j))){
tag=1;
if((z[wei]&(1<<j))<(f[wei]&(1<<j)))ans^=1;
break;
}
if(!tag){
set<int>::iterator it=s.upper_bound(wei);
if(it!=s.end()){
int x=*it;
for(int j=29;j>=0;--j){
if((z[x]&(1<<j))!=(f[x]&(1<<j))){
tag=1;
if((z[x]&(1<<j))<(f[x]&(1<<j)))ans^=1;
break;
}
}
}
}
printf("%d
",ans);
}
}
return 0;
}