1. 程式人生 > >bzoj 5294: [Bjoi2018]二進位制【動態dp+線段樹】

bzoj 5294: [Bjoi2018]二進位制【動態dp+線段樹】

不太清楚是不是動態dp……?
這個維護其實和最大連續子段差不多,維護l[x][y],r[x][y],m[x][y]分別表示包含左兒子的01個數為(x,y)的區間個數,包含右兒子的01個數為(x,y)的區間個數,和01個數為(x,y)的所有區間個數
x表示1的個數情況,0表示0個,1表示1個,2表示>=2的偶數個,3表示>=3的奇數個
y表示0的個數情況,0表示0個,1表示1個,2表示>=2個
轉移的話合併ls.r,rs.l即可,注意是乘法,注意細節,轉移很難寫……

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
int n,m,a[N];
struct xds
{
    long long l[4][3],r[4][3],m[4][3],s[2];
}t[N<<2];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int wk1(int x) 
{
    return (x<=1)?x:(x%2+2);
}
 
int wk0(int x) 
{
    return (x<=1)?x:2;
}
xds operator + (const xds &a,const xds &b)
{
    xds c;
    c.s[0]=a.s[0]+b.s[0];
    c.s[1]=a.s[1]+b.s[1];
    for(int i=0;i<=3;i++)
        for(int j=0;j<=2;j++)
        {
            c.l[i][j]=a.l[i][j];
            c.r[i][j]=b.r[i][j];
            c.m[i][j]=a.m[i][j]+b.m[i][j];
        }
    for(int i=0;i<=3;i++)
        for(int j=0;j<=2;j++)
            if(a.r[i][j])
                for(int k=0;k<=3;k++)
                    for(int l=0;l<=2;l++)
                        if(b.l[k][l])
                            c.m[wk1(i+k)][wk0(j+l)]+=a.r[i][j]*b.l[k][l];
    for(int i=0;i<=3;i++)
        for(int j=0;j<=2;j++)
        {
            c.l[wk1(a.s[1]+i)][wk0(a.s[0]+j)]+=b.l[i][j];
            c.r[wk1(b.s[1]+i)][wk0(b.s[0]+j)]+=a.r[i][j];
        }
    return c;
}
void build(int ro,int l,int r)
{
    if(l==r)
    {
        int x=(a[l]==1),y=(a[l]==0);
        t[ro].s[0]=y,t[ro].s[1]=x;
        t[ro].m[x][y]=t[ro].l[x][y]=t[ro].r[x][y]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(ro<<1,l,mid);
    build(ro<<1|1,mid+1,r);
    t[ro]=t[ro<<1]+t[ro<<1|1];
}
void update(int ro,int l,int r,int p)
{
    if(l==r)
    {
        int x=t[ro].s[1],y=t[ro].s[0];
        t[ro].m[x][y]=t[ro].l[x][y]=t[ro].r[x][y]=0;
        swap(t[ro].s[0],t[ro].s[1]);
        t[ro].m[y][x]=t[ro].l[y][x]=t[ro].r[y][x]=1;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)
        update(ro<<1,l,mid,p);
    else
        update(ro<<1|1,mid+1,r,p);
    t[ro]=t[ro<<1]+t[ro<<1|1];
}
xds ques(int ro,int l,int r,int x,int y)
{
    if(l==x&&r==y)
        return t[ro];
    int mid=(l+r)>>1;
    if(y<=mid)
        return ques(ro<<1,l,mid,x,y);
    else if(x>mid)
        return ques(ro<<1|1,mid+1,r,x,y);
    else
        return ques(ro<<1,l,mid,x,mid)+ques(ro<<1|1,mid+1,r,mid+1,y);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    build(1,1,n);
    m=read();
    while(m--)
    {
        int o=read();
        if(o==1)
        {
            int x=read();
            update(1,1,n,x);
        }
        else
        {
            int l=read(),r=read();
            xds x=ques(1,1,n,l,r);
            printf("%lld\n",x.m[0][0]+x.m[0][1]+x.m[0][2]+x.m[2][0]+x.m[2][1]+x.m[2][2]+x.m[3][2]);
        }
    }
    return 0;
}