hdu 5068&&2019牛客网暑假多校训练赛E 线段树+矩阵乘法

hdu 2068 

#include
using namespace std;
//用线段树维护一个2*2的矩阵,a[i][j]表示从这一层第i个门到下一层第j个门是否联通,
//第i层到第j层之间的矩阵相乘之后的结果矩阵,各元素和为从第i层到第j层的种类数
const int mod=1000000007;
struct mat{
    long long a[2][2];
}tr[400005];
mat mul(mat x,mat y)
{
    mat ne;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            ne.a[i][j]=0;
            for(int k=0;k<2;k++)
            {
                ne.a[i][j]=(ne.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
            }
        }
    }
    return ne;
}
void build(int i,int l,int r)
{
    if(l==r)
    {
        for(int ii=0;ii<2;ii++)
        {
            for(int j=0;j<2;j++)
                tr[i].a[ii][j]=1;
        }
        return ;
    }
    int mid=l+r>>1;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tr[i]=mul(tr[i*2],tr[i*2+1]);
}
void update(int i,int l,int r,int x,int y,int z)
{
    if(l==r)
    {
        tr[i].a[y][z]^=1;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid)
    update(i*2,l,mid,x,y,z);
    else
        update(i*2+1,mid+1,r,x,y,z);
    tr[i]=mul(tr[i*2],tr[i*2+1]);
}
mat query(int i,int l,int r,int x,int y)
{
    if(l>=x&&r<=y)
    {
        return tr[i];
    }
    int mid=l+r>>1;
    mat ans;
    for(int ii=0;ii<2;ii++)
    {
        for(int j=0;j<2;j++)
        {
            if(ii==j)
                ans.a[ii][j]=1;
            else
                ans.a[ii][j]=0;
        }
    }
    if(x<=mid)
        ans=mul(ans,query(i*2,l,mid,x,y));
    if(y>mid)
        ans=mul(ans,query(i*2+1,mid+1,r,x,y));
    return ans;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        build(1,1,n);
        int op,x,y,z;
        while(m--)
        {
            scanf("%d",&op);
            if(op==0)
            {
                scanf("%d%d",&x,&y);
                mat t=query(1,1,n,x,y-1);
                long long ans=0;
                for(int i=0;i<2;i++)
                {
                    for(int j=0;j<2;j++)
                        ans+=t.a[i][j],ans%=mod;
                }
                printf("%lld\n",ans);
            }
            else
            {
                scanf("%d%d%d",&x,&y,&z);
                update(1,1,n,x,y-1,z-1);
            }
        }
    }
    return 0;
}

多校E 

#include
using namespace std;
int n,m,q;
int b[50010][20];
const int mod=1000000007;
char s[30];
struct mat{
    long long a[11][11];
   friend mat operator *(const mat &a,const mat &b)//行与行之间的关系通过乘的形式进行转换
    {
        mat c;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=m;j++)
            {
                c.a[i][j]=0;
                for(int k=1;k<=m;k++)
                    c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
            }
        }
        return c;
    }
}tr[300040];//tr[1].a[i][j]表示所有行乘积后,从第b[1][i]到b[n][j]有多少可行路线
void work(int b[],mat &ans)//在这一行中ans.a[i][j]表示在在b这一行中是否能从i到j
{
    memset(ans.a,0,sizeof(ans.a));
    for(int i=1;i<=m;i++)
    {
        int j=i;
        for(;j>=1&&!b[j];ans.a[i][j]=1,j--);
        j=i;
        for(;j<=m&&!b[j];ans.a[i][j]=1,j++);
    }
}
void build(int i,int l,int r)
{
    if(l==r)
    {
        work(b[l],tr[i]);
        return ;
    }
    int mid=l+r>>1;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tr[i]=tr[i*2]*tr[i*2+1];
}
void update(int i,int l,int r,int x)
{
    if(l==r)
    {
        work(b[l],tr[i]);
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)
        update(i*2,l,mid,x);
    else
        update(i*2+1,mid+1,r,x);
    tr[i]=tr[i*2]*tr[i*2+1];
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
        b[i][j]=s[j]-'0';
    }
    build(1,1,n);
    while(q--)
    {
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)
        {
            b[x][y]^=1;
            update(1,1,n,x);
        }
        else
            printf("%lld\n",tr[1].a[x][y]);
    }
    return 0;
}

 

你可能感兴趣的:(线段树)