[线段树维护BITSET] NOI2017 .Day1 T1 整数

把数转换成二进制维护
那么进位就是把之后一段连续1变成0,后面的0变成1
退位就是把之后一段连续的0变成1,后面的1变成0
这样可以用线段树维护
有一个 nlog2n 的暴力,就是把这个数的每一个为1的位取出来,用线段树加进去,a为负的同理

如果把原来的01序列压位一下(我压了30位),那么a最多跨2个30位整数,把这两位取出来,拼成一个60位整数,然后把加上去,因为最多进(退)一位,按上面的方法维护就可以了

#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int N=2e6+10,base=30,MAX=2e6,ALL1=(1LL<1,ALL0=0;
const ll inf=1LL<<60;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
  char c=nc(),f=1; x=0;
  for(;c>'9'||c<'0';(f=c=='-'?-f:f),c=nc());for(;c>='0'&&c<='9';x=x*10+f*(c-'0'),c=nc());
}

int n,t,type,a,b,k;
bool a0[N<<2],a1[N<<2];
int num[N<<2],tag[N<<2];
int fir0[1<<16],fir1[1<<16];

inline void Up(int g){
  a0[g]=a0[g<<1] && a0[g<<1|1];
  a1[g]=a1[g<<1] && a1[g<<1|1];
}

inline void set0(int g){ num[g]=ALL0; tag[g]=0; a0[g]=1; a1[g]=0; }
inline void set1(int g){ num[g]=ALL1; tag[g]=1; a1[g]=1; a0[g]=0; }

inline void Push(int g){
  if(~tag[g])
    if(tag[g]) set1(g<<1),set1(g<<1|1);
    else set0(g<<1),set0(g<<1|1);
  tag[g]=-1;
}

int Query(int g,int x,int L,int R){
  if(L==R) return num[g];
  int mid=L+R>>1; Push(g);
  if(x<=mid) return Query(g<<1,x,L,mid);
  else return Query(g<<1|1,x,mid+1,R);
}

int Find0(int g,int l,int r,int L,int R){
  if(L==R) return num[g]!=ALL1?L:-1;
  int mid=L+R>>1; Push(g);
  if(l==L&&r==R){
    if(!a1[g<<1]) return Find0(g<<1,l,mid,L,mid);
    return Find0(g<<1|1,mid+1,r,mid+1,R);
  }
  if(r<=mid) return Find0(g<<1,l,r,L,mid);
  if(l>mid) return Find0(g<<1|1,l,r,mid+1,R);
  int ret=Find0(g<<1,l,mid,L,mid);
  if(~ret) return ret;
  return Find0(g<<1|1,mid+1,r,mid+1,R);
}

int Find1(int g,int l,int r,int L,int R){
  if(L==R) return num[g]!=ALL0?L:-1;
  int mid=L+R>>1; Push(g);
  if(l==L&&r==R){
    if(!a0[g<<1]) return Find1(g<<1,l,mid,L,mid);
    return Find1(g<<1|1,mid+1,r,mid+1,R);
  }
  if(r<=mid) return Find1(g<<1,l,r,L,mid);
  if(l>mid) return Find1(g<<1|1,l,r,mid+1,R);
  int ret=Find1(g<<1,l,mid,L,mid);
  if(~ret) return ret;
  return Find1(g<<1|1,mid+1,r,mid+1,R);
}

void Modify(int g,int x,int y,int L,int R){
  if(L==R){
    num[g]=y; a0[g]=y==ALL0; a1[g]=y==ALL1;
    return ;
  }
  int mid=L+R>>1; Push(g);
  if(x<=mid) Modify(g<<1,x,y,L,mid);
  else Modify(g<<1|1,x,y,mid+1,R);
  Up(g);
}

void Cover0(int g,int l,int r,int L,int R){
  if(l==L&&r==R) return set0(g),void("%%%%gjghfd%%%%");
  int mid=L+R>>1; Push(g);
  if(r<=mid) Cover0(g<<1,l,r,L,mid);
  else if(l>mid) Cover0(g<<1|1,l,r,mid+1,R);
  else Cover0(g<<1,l,mid,L,mid),Cover0(g<<1|1,mid+1,r,mid+1,R);
  Up(g);
}

void Cover1(int g,int l,int r,int L,int R){
  if(l==L&&r==R) return set1(g),void("%%%%gjghfd%%%%");
  int mid=L+R>>1; Push(g);
  if(r<=mid) Cover1(g<<1,l,r,L,mid);
  else if(l>mid) Cover1(g<<1|1,l,r,mid+1,R);
  else Cover1(g<<1,l,mid,L,mid),Cover1(g<<1|1,mid+1,r,mid+1,R);
  Up(g);
}

inline void Out(){
  return ;
  puts("-----");
  //for(int i=1;i<=20;i++) 
  //    printf("%d ",Query(1,i,1,MAX));
  printf("%d ",Query(1,46488,1,MAX));
  puts("\n-----");
}

int main(){
  rea(n); rea(t); rea(t); rea(t);
  memset(a0,1,sizeof(a0)); memset(tag,-1,sizeof(tag));
  fir0[1]=1; fir1[1]=0; fir1[0]=15;
  for(int i=2;i<1<<15;i++)
    fir0[i]=i&1?fir0[i>>1]+1:0,fir1[i]=i&1?0:fir1[i>>1]+1;
  while(n--){
    rea(type);
    if(type&1){
      rea(a); rea(b);
      if(a>0){  
    int pos=b/base+1; ll cur=((ll)a<<(b%base))+((ll)Query(1,pos+1,1,MAX)<1,pos,1,MAX);
    if(cur>=inf){
      cur-=inf;
      int p=Find0(1,pos+2,MAX,1,MAX),q=Query(1,p,1,MAX);
      if(pos+21,pos+2,p-1,1,MAX);
      int w=fir0[q&32767]<15?fir0[q&32767]:fir0[q>>15]+15;
      q^=(1<1)-1;
      Modify(1,p,q,1,MAX);
    }
    Modify(1,pos+1,cur>>base,1,MAX); Modify(1,pos,cur&ALL1,1,MAX);
      }
      else{
    a=-a;
    int pos=b/base+1; ll cur=((ll)Query(1,pos+1,1,MAX)<1,pos,1,MAX)-((ll)a<<(b%base));
    if(cur<0){
      cur+=inf;
      int p=Find1(1,pos+2,MAX,1,MAX),q=Query(1,p,1,MAX);
      if(pos+21,pos+2,p-1,1,MAX);
      int w=fir1[q&32767]<15?fir1[q&32767]:fir1[q>>15]+15;
      q^=(1<1)-1;
      Modify(1,p,q,1,MAX);
    }
    Modify(1,pos+1,cur>>base,1,MAX); Modify(1,pos,cur&ALL1,1,MAX);
      }
    }
    else{
      rea(k);
      int pos=k/base+1,Q=Query(1,pos,1,MAX); k%=base;
      if(Q>>k&1) puts("1"); else puts("0");
    }
    Out();
  }
  return 0;
}

你可能感兴趣的:(线段树,压位)