bzoj5294: [Bjoi2018]二进制【动态规划+线段树】

Description

pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是333 的倍数。他想研究对于二进
制,是否也有类似的性质。于是他生成了一个长为n 的二进制串,希望你对于这个二进制串的一个子区间,能求出
其有多少位置不同的连续子串,满足在重新排列后(可包含前导0 )是一个3 的倍数。两个位置不同的子区间指开
始位置不同或结束位置不同。由于他想尝试尽量多的情况,他有时会修改串中的一个位置,并且会进行多次询问。

Input

输入第一行包含一个正整数n ,表示二进制数的长度。
之后一行n 个空格隔开的整数,保证均是0 或1 ,表示该二进制串。
之后一行一个整数m ,表示询问和修改的总次数。
之后m 行每行为1 i,表示pupil 修改了串的第i个位置(0 变成1 或1 变成0 ),或2 l r
表示pupil 询问的子区间是[l,r] 。
串的下标从1 开始。
1≤n,m≤100000

Output

对于每次询问,输出一行一个整数表示对应该询问的结果。

Sample Input

4

1 0 1 0

3

2 1 3

1 3

2 3 4

Sample Output

2

3

说明

样例解释

对于第一个询问,区间[2,2] 只有数字0 ,是3 的倍数,区间[1,3]

可以重排成011(2)=3(10),是3 的倍数,其他区间均不能重排成3 的倍数。

对于第二个询问,全部三个区间均能重排成3 的倍数(注意00 也是合法的)。

解题思路:

考虑用总数减去不合法区间数。
可以得到结论,不能组成3的倍数的就只有2种情况。
1.只有1个1的区间;
2.有奇数个1且少于2个0的区间。
我们可以用两颗线段树分别维护动态规划计算这两种区间的个数,但发现两种都包含了1,10,01三种区间,所以再用两个树状数组维护以上三种区间个数加回去即可

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=100005;
int n,m,a[N];
struct BIT
{
    int a[N];
    inline void add(int i,int x){for(;i<=n;i+=i&-i)a[i]+=x;}
    inline int query(int i){int res=0;for(;i;i-=i&-i)res+=a[i];return res;}
    inline int Query(int l,int r){return query(r)-query(l-1);}
}bit1,bit2;
struct Segtree1
{
    ll f[N<<2][4][2][2];
    inline void update(int p,int p1,int p2)
    {
        for(int i=0;i<=1;i++)for(int k=0;k<=1;k++)
        {
            f[p][0][i][k]=f[p1][0][i][k]+f[p2][0][i][k]+f[p1][2][i][k]+f[p2][1][i][k];
            f[p][1][i][k]=f[p1][3][i][k]+f[p1][1][i][k];
            f[p][2][i][k]=f[p2][3][i][k]+f[p2][2][i][k];
            f[p][3][i][k]=0;
        }
        for(int i=0;i<=1;i++)for(int j=0;i+j<=1;j++)
        {
            f[p][0][0][i+j]+=f[p1][2][0][i]*f[p2][1][0][j]+f[p1][2][1][i]*f[p2][1][1][j];
            f[p][0][1][i+j]+=f[p1][2][0][i]*f[p2][1][1][j]+f[p1][2][1][i]*f[p2][1][0][j];
            f[p][1][0][i+j]+=f[p1][3][0][i]*f[p2][1][0][j]+f[p1][3][1][i]*f[p2][1][1][j];
            f[p][1][1][i+j]+=f[p1][3][0][i]*f[p2][1][1][j]+f[p1][3][1][i]*f[p2][1][0][j];
            f[p][2][0][i+j]+=f[p1][2][0][i]*f[p2][3][0][j]+f[p1][2][1][i]*f[p2][3][1][j];
            f[p][2][1][i+j]+=f[p1][2][0][i]*f[p2][3][1][j]+f[p1][2][1][i]*f[p2][3][0][j];
            f[p][3][0][i+j]+=f[p1][3][0][i]*f[p2][3][0][j]+f[p1][3][1][i]*f[p2][3][1][j];
            f[p][3][1][i+j]+=f[p1][3][0][i]*f[p2][3][1][j]+f[p1][3][1][i]*f[p2][3][0][j];
        }
    }
    inline void build(int p,int l,int r)
    {
        if(l==r){a[l]?f[p][3][1][0]=1:f[p][3][0][1]=1;return;}
        int mid=l+r>>1;
        build(p<<1,l,mid),build(p<<1|1,mid+1,r);
        update(p,p<<1,p<<1|1);
    }
    inline void modify(int p,int l,int r,int pos)
    {
        if(l==r)
        {
            if(a[l])f[p][3][1][0]=1,f[p][3][0][1]=0;
            else f[p][3][0][1]=1,f[p][3][1][0]=0;
            return;
        }
        int mid=l+r>>1;
        pos<=mid?modify(p<<1,l,mid,pos):modify(p<<1|1,mid+1,r,pos);
        update(p,p<<1,p<<1|1);
    }
    inline void query(int p,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y)
        {
            for(int i=0;i<=3;i++)
                for(int j=0;j<=1;j++)
                    for(int k=0;k<=1;k++)
                        f[4*n+1][i][j][k]=f[0][i][j][k];
            update(0,4*n+1,p);
            return;
        }
        int mid=l+r>>1;
        if(x<=mid)query(p<<1,l,mid,x,y);
        if(y>mid)query(p<<1|1,mid+1,r,x,y);
    }
    inline ll Query(int l,int r)
    {
        for(int i=0;i<=3;i++)
            for(int j=0;j<=1;j++)
                for(int k=0;k<=1;k++)
                    f[0][i][j][k]=0;
        query(1,1,n,l,r);ll res=0;
        for(int i=0;i<=3;i++)res+=f[0][i][1][0]+f[0][i][1][1];
        return res;
    }
}T1;
struct Segtree2
{
    ll f[N<<2][4][2];
    inline void update(int p,int p1,int p2)
    {
        for(int i=0;i<=1;i++)
        {
            f[p][0][i]=f[p1][0][i]+f[p2][0][i]+f[p1][2][i]+f[p2][1][i];
            f[p][1][i]=f[p1][3][i]+f[p1][1][i];
            f[p][2][i]=f[p2][3][i]+f[p2][2][i];
            f[p][3][i]=0;
        }
        for(int i=0;i<=1;i++)for(int j=0;i+j<=1;j++)
        {
            f[p][0][i+j]+=f[p1][2][i]*f[p2][1][j];
            f[p][1][i+j]+=f[p1][3][i]*f[p2][1][j];
            f[p][2][i+j]+=f[p1][2][i]*f[p2][3][j];
            f[p][3][i+j]+=f[p1][3][i]*f[p2][3][j];
        }
    }
    inline void build(int p,int l,int r)
    {
        if(l==r){a[r]?f[p][3][1]=1:f[p][3][0]=1;return;}
        int mid=l+r>>1;
        build(p<<1,l,mid),build(p<<1|1,mid+1,r);
        update(p,p<<1,p<<1|1);
    }
    inline void modify(int p,int l,int r,int pos)
    {
        if(l==r)
        {
            if(a[r])f[p][3][1]=1,f[p][3][0]=0;
            else f[p][3][0]=1,f[p][3][1]=0;
            return;
        }
        int mid=l+r>>1;
        pos<=mid?modify(p<<1,l,mid,pos):modify(p<<1|1,mid+1,r,pos);
        update(p,p<<1,p<<1|1);
    }
    inline void query(int p,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y)
        {
            for(int i=0;i<=3;i++)
                for(int j=0;j<=1;j++)
                    f[4*n+1][i][j]=f[0][i][j];
            update(0,4*n+1,p);
            return;
        }
        int mid=l+r>>1;
        if(x<=mid)query(p<<1,l,mid,x,y);
        if(y>mid)query(p<<1|1,mid+1,r,x,y);
    }
    inline ll Query(int l,int r)
    {
        for(int i=0;i<=3;i++)
            for(int j=0;j<=1;j++)
                f[0][i][j]=0;
        query(1,1,n,l,r);ll res=0;
        for(int i=0;i<=3;i++)res+=f[0][i][1];
        return res;
    }
}T2;
int main()
{
    //freopen("binary.in","r",stdin);
    //freopen("binary.out","w",stdout);
    n=getint();
    for(int i=1;i<=n;i++)a[i]=getint();
    T1.build(1,1,n),T2.build(1,1,n);
    for(int i=1;i<=n;i++)
    {
        if(a[i])bit1.add(i,1);
        if(i<n&&(a[i]^a[i+1]))bit2.add(i,1);
    }
    int op,l,r;
    for(m=getint();m;m--)
    {
        op=getint();
        if(op==1)
        {
            l=getint(),a[l]^=1;
            T1.modify(1,1,n,l),T2.modify(1,1,n,l),bit1.add(l,a[l]?1:-1);
            if(l<n)bit2.add(l,(a[l]^a[l+1])?1:-1);
            if(l>1)bit2.add(l-1,(a[l-1]^a[l])?1:-1);
        }
        else
        {
            l=getint(),r=getint();ll len=r-l+1;
            cout<<len*(len+1)/2-T1.Query(l,r)-T2.Query(l,r)+bit1.Query(l,r)+bit2.Query(l,r-1)<<'\n';
        }
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值