[BZOJ2628][压位][Shift-And&Shift-Or]JZPSTR

%%%Hillan

学了发Shift-And算法
再手打个Bitset就可以了

表示Bitset调了一天,调到最后查询出问题了……

#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#define N 2000010

using namespace std;

typedef unsigned int uint;

int cou[1<<17];

inline int Count(uint a){
  return cou[a&65535]+cou[a>>16];
}

struct Bitset{
  uint A[N/32+15]; int len;
  Bitset(){ len=0; memset(A,0,sizeof(A)); }
  void set0(int B,int W){ A[B]&=~(1U<<W); }
  void set1(int B,int W){ A[B]|=(1U<<W); }
  void shr(int x,int y){
    int E=len>>5,B=x>>5,S=y>>5,w=y&31,v=(32-w)&31;
    A[E+S+1]=0;
    for(int i=E;i>B;i--)
      A[i+S+1]|=v?A[i]>>v:0,A[i+S]=A[i]<<w;
    for(int i=(B<<5)+31;i>=x;i--)
      insert(i+y,(A[i>>5]>>(i&31))&1);
    len+=y;
  }
  void shl(int x,int y){
    int E=len>>5,B=x>>5,S=y>>5,w=y&31,v=(32-w)&31;
    len-=y; 
    for(int i=x;i<=(B<<5)+31;i++)
      insert(i,(A[i+y>>5]>>((i+y)&31))&1);
    for(int i=B+1;i<=E;i++)
      A[i]=A[i+S]>>w,A[i]|=v?A[i+S+1]<<v:0;
  }
  void insert(int x,int y){
    int B=x>>5,w=x&31; 
    if(y) set1(B,w); else set0(B,w);
  }
  void And(int x,int y,Bitset B){
    x>>=5; y>>=5;
    for(int i=x;i<=y;i++) A[i]&=B.A[i];
  }
  Bitset sub(int a,int b){
    a>>=5; b>>=5;
    Bitset c; c.len=len;
    for(int i=a;i<=b;i++) c.A[i]=A[i];
    return c;
  }
  int count(int l,int r){
    int S=l>>5,E=r>>5,R=0;
    l&=31; r&=31;
    if(S==E) return Count((A[S]>>l)&((1<<r-l+1)-1));
    for(int i=S+1;i<=E-1;i++) R+=Count(A[i]);
    R+=Count(A[S]>>l)+Count(A[E]<<31-r);
    return R;
  }
}f[10],S;

int n,op,l,r,length,x,y;
int inc[1000010];

inline void First(){
  for(int i=1;i<(1<<16);i++)
    cou[i]=cou[i>>1]+(i&1);
}

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

inline void reaD(int &x){
  char c=nc(); x=0;
  for(;c>57||c<48;c=nc());for(;c>=48&&c<=57;x=x*10+c-48,c=nc());
}

inline void reaD(int *x){
  char c=nc(); length=0;
  for(;c>57||c<48;c=nc());for(;c>=48&&c<=57;x[++length]=c-48,c=nc());
}

int main(){
  First(); reaD(n);
  while(n--){
    reaD(op);
    if(op==0){
      reaD(x); reaD(inc);
      for(int i=0;i<10;i++) f[i].shr(x,length);
      for(int i=1;i<=length;i++)
    for(int j=0;j<10;j++)
      if(j==inc[i]) f[j].insert(i+x-1,1);
      else f[j].insert(i+x-1,0);
    }
    else if(op==1){
      reaD(x); reaD(y); y-=x;
      if(!y) continue;
      for(int i=0;i<10;i++) f[i].shl(x,y);
    }
    else{
      reaD(x); reaD(y); reaD(inc);
      if(y-x<length){ puts("0"); continue; }
      S=f[inc[1]].sub(x,y);
      for(int i=2;i<=length;i++){
        S.shr(x,1);
    S.And(x,y,f[inc[i]]);
      }
      printf("%d\n",S.count(x+length-1,y-1));
    }
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值