wannafly 17D 01序列2

水题。

假设有两个二进制数a,b,c=a+b(a,b拼接起来)

那么显然如果b长度为偶数\(c\mod 3=(b\mod 3+a\mod 3)\mod 3\)

否则\(c\mod 3=(b\mod 3+(a\mod 3)*2)\mod 3\)

那么只要记一个区间的前缀和后缀就行了,合并的时候左儿子的后缀和右儿子的前缀合并。

具体见代码

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int a[500010];
struct yyb{
    bool len;
    ll l[3][2],r[3],ans,num;
    //len表示长度是奇数/偶数
    //l[i][j]表示长度为奇数/偶数膜3余0/1/2的前缀数量
    //r[i]表示膜3余0/1/2的前缀数量
    //ans表示答案
    //num表示这个区间膜3
}s[500010<<2];
il yyb operator +(const yyb&a,const yyb&b){
    yyb c;
    c.len=a.len^b.len;
    for(int i=0;i<3;++i)c.l[i][0]=a.l[i][0],c.l[i][1]=a.l[i][1],c.r[i]=b.r[i];
    c.ans=a.ans+b.ans;
    for(int i=0;i<3;++i)//答案加上中间部分
        for(int j=0;j<3;++j)
            for(int k=0;k<2;++k)
                if((i*(k?2:1)+j)%3==0)c.ans+=a.r[i]*b.l[j][k];
    for(int i=0;i<3;++i)
        for(int j=0;j<2;++j)
            c.l[(a.num*(j?2:1)+i)%3][j^a.len]+=b.l[i][j];
    for(int i=0;i<3;++i)c.r[(i*(b.len?2:1)+b.num)%3]+=a.r[i];
    c.num=(a.num*(b.len?2:1)+b.num)%3;
    return c;
}
#define mid ((l+r)>>1)
il vd set(int x,int p){
    s[x].len=1;
    memset(s[x].l,0,sizeof s[x].l);
    memset(s[x].r,0,sizeof s[x].r);
    s[x].ans=!a[p];s[x].num=a[p];
    s[x].l[a[p]][1]=s[x].r[a[p]]=1;
}
il vd build(int x,int l,int r){
    if(l==r){set(x,l);return;}
    build(x<<1,l,mid),build(x<<1|1,mid+1,r);
    s[x]=s[x<<1]+s[x<<1|1];
}
il vd update(int x,int l,int r,const int&p){
    if(l==r){set(x,l);return;}
    if(p<=mid)update(x<<1,l,mid,p);
    else update(x<<1|1,mid+1,r,p);
    s[x]=s[x<<1]+s[x<<1|1];
}
il yyb query(int x,int l,int r,const int&L,const int&R){
    if(L<=l&&r<=R)return s[x];
    if(L<=mid)
        if(mid<R)return query(x<<1,l,mid,L,R)+query(x<<1|1,mid+1,r,L,R);
        else return query(x<<1,l,mid,L,R);
    else return query(x<<1|1,mid+1,r,L,R);
}
int main(){
    int n=gi(),m=gi();
    for(int i=1;i<=n;++i)a[i]=gi();
    build(1,1,n);
    int o,l,r;
    while(m--){
        o=gi(),l=gi();
        if(o==1)a[l]^=1,update(1,1,n,l);
        else r=gi(),printf("%lld\n",query(1,1,n,l,r).ans);
    }
    return 0;
}
posted @ 2018-11-01 21:29  菜狗xzz  阅读(166)  评论(0编辑  收藏  举报