[NOI2017]整数

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\n",ans);
    }
  }
  return 0;
}
posted @ 2019-05-28 11:38  comld  阅读(162)  评论(0编辑  收藏  举报