【BZOJ】5294: [Bjoi2018]二进制-动态DP&线段树

传送门:bzoj5294


题解

一个二进制数是三的倍数,当且仅当有偶数个1 或者 有三个及以上的1和两个及以上的0。

不合法的区间即为有1个1 或 奇数个1&0/1个0的情况。

线段树维护即可,打标记有点麻烦。。。


代码

#include
#define lc k<<1
#define rc k<<1|1
#define mem(f) memset((f),0,sizeof((f)))
using namespace std;
const int N=1e5+10;
typedef long long ll;

int n,m,ini[N],pr;

char cp;
inline void rd(int &x)
{
    cp=getchar();x=0;
    for(;!isdigit(cp);cp=getchar());
    for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}

struct Ag{
    
   struct node{
   	  ll a[4][2][2],b[4][2];
   }t[N<<2],rep;
   
   inline node merge(node l,node r)
   {
   	    node k;int i,j,ii,jj,v,vv;
   	    for(i=0;i<2;++i){
   	    	for(j=0;j<2;++j){
   	    		k.a[0][i][j]=l.a[0][i][j]+r.a[0][i][j]+l.a[2][i][j]+r.a[1][i][j];
   	    	    k.a[1][i][j]=l.a[1][i][j]+l.a[3][i][j];
   	    	    k.a[2][i][j]=r.a[2][i][j]+r.a[3][i][j];
   	    	    k.a[3][i][j]=0LL;
            }
   	    	k.b[0][i]=l.b[0][i]+r.b[0][i]+l.b[2][i]+r.b[1][i];
   	    	k.b[1][i]=l.b[1][i]+l.b[3][i];
   	    	k.b[2][i]=r.b[2][i]+r.b[3][i];
   	    	k.b[3][i]=0LL;
   	    }
   	    for(i=0;i<2;++i)
   	     for(j=0;i+j<2;++j){
   	     	v=i+j;
   	     	for(ii=0;ii<2;++ii)
   	     	 for(jj=0;jj<2;++jj){
   	     	 	 vv=(ii+jj)&1;
   	     	 	 k.a[0][vv][v]+=l.a[2][ii][i]*r.a[1][jj][j];
   	     	     k.a[1][vv][v]+=l.a[3][ii][i]*r.a[1][jj][j];
   	     	     k.a[2][vv][v]+=l.a[2][ii][i]*r.a[3][jj][j];
   	     	     k.a[3][vv][v]+=l.a[3][ii][i]*r.a[3][jj][j];
            }
   	     	k.b[0][v]+=l.b[2][i]*r.b[1][j];
   	     	k.b[1][v]+=l.b[3][i]*r.b[1][j];
   	        k.b[2][v]+=l.b[2][i]*r.b[3][j];
   	     	k.b[3][v]+=l.b[3][i]*r.b[3][j];
   	     }
   	    return k;
   }
   
   void build(int k,int l,int r)
   {
   	   if(l==r) {
           t[k].a[3][ini[l]][ini[l]^1]=1LL;
           t[k].b[3][ini[l]]=1LL;
           return;
       }
   	   int mid=(l+r)>>1;
   	   build(lc,l,mid);build(rc,mid+1,r);
   	   t[k]=merge(t[lc],t[rc]);
   }
   
   void change(int k,int l,int r,int pos)
   {
   	   if(l==r){
   	   	  mem(t[k].a[3]);mem(t[k].b[3]);
          t[k].a[3][ini[l]][ini[l]^1]=1LL;
          t[k].b[3][ini[l]]=1LL;
          return;
       } 
       int mid=(l+r)>>1;
       if(pos<=mid) change(lc,l,mid,pos);
       else change(rc,mid+1,r,pos);
       t[k]=merge(t[lc],t[rc]);
   }
   
   node query(int k,int l,int r,int L,int R)
   {
   	   if(L<=l && r<=R) return t[k];
   	   int mid=(l+r)>>1;
   	   if(R<=mid) return query(lc,l,mid,L,R);
   	   if(L>mid) return query(rc,mid+1,r,L,R);
   	   return merge(query(lc,l,mid,L,R),query(rc,mid+1,r,L,R));
   } 
   
   inline ll gt(int x,int y)
   {
      rep=query(1,1,n,x,y);
      ll re=0;int i,j;
      for(i=0;i<4;++i){
      	for(j=0;j<2;++j) re+=rep.a[i][1][j];
        re+=rep.b[i][1];
      }
      return re;
   } 
}sg;

struct bit{
    ll tre[2][N];
    
    void ad(int id,int x,int v)
    {for(;x<=n;x+=(x&(-x))) tre[id][x]+=v;}
    
    inline ll query(int id,int x)
    {
        ll re=0;
        for(;x;x-=(x&(-x))) re+=tre[id][x];
        return re;
    } 
    
    inline ll gt(int x,int y)
    {return query(1,y)-query(1,x)+query(0,y)-query(0,x-1);}
    
}bit;

int main(){
    int op,x,y,z,i;
    rd(n);
    for(i=1;i<=n;++i){
       rd(ini[i]);
       if(ini[i]) bit.ad(0,i,1);
       if(i>1 && (ini[i-1]^ini[i])) bit.ad(1,i,1);
    }
    sg.build(1,1,n);int TK=0;
    for(rd(m);m;--m){
        ++TK;
        rd(op);rd(x);
        if(op==1){
            ini[x]^=1;
            sg.change(1,1,n,x);
            bit.ad(0,x,ini[x]?1:(-1));
            if(x>1)
              bit.ad(1,x,(ini[x]==ini[x-1])?(-1):1);
            if(x

你可能感兴趣的:(线段树,动态DP)