zoukankan      html  css  js  c++  java
  • wannafly 17D 01序列2

    水题。

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

    那么显然如果b长度为偶数(cmod 3=(bmod 3+amod 3)mod 3)

    否则(cmod 3=(bmod 3+(amod 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
    ",query(1,1,n,l,r).ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Linux
    Linux
    Linux
    Linux
    Linux
    shell tr命令
    grep 正则表达
    shell 运算符
    shell 重定向
    bzoj 1026 DP,数位统计
  • 原文地址:https://www.cnblogs.com/xzz_233/p/9892666.html
Copyright © 2011-2022 走看看