HDU-5068-Harry And Math Teacher(线段树)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5068

根据每层两个点的到下一层两个点的连接情况,可以得到一个2*2的矩阵,初始矩阵全部联通都为1,不连通为0,显然一段区间内的方案数就是区间内矩阵相乘后的矩阵行列值求和。简单的线段树维护区间矩阵乘积就好。


#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
#include <string>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 50005
#define MAXM 4500000
const long long mod=1000000007;

struct Mat
{
    long long a[2][2];
}mat[MAXN<<2];

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 poi, int x, int y)
{
    if(x==y)
    {
        for(int i=0; i<2; ++i)for(int j=0; j<2; ++j)
            mat[poi].a[i][j]=1;
        return ;
    }
    int mid=(x+y)>>1;
    build(poi<<1,x,mid);
    build(poi<<1^1,mid+1,y);
    mat[poi]=Mul(mat[poi<<1], mat[poi<<1^1]);
}
Mat query(int poi, int l, int r, int x, int y)
{
    if(l>=x&&r<=y)
    {
        return mat[poi];
    }
    int mid=(l+r)>>1;
    if(mid>=y)return query(poi<<1,l,mid,x,y);
    if(mid<x)return query(poi<<1^1,mid+1,r,x,y);
    return Mul(query(poi<<1,l,mid,x,y),query(poi<<1^1,mid+1,r,x,y));
}
void change(int poi, int x, int y, int A, int B, int temp)
{
    if(x==y)
    {
        mat[poi].a[A][B]^=1;
        return ;
    }
    int mid=(x+y)>>1;
    if(temp<=mid)change(poi<<1,x,mid,A,B,temp);
    else change(poi<<1^1,mid+1,y,A,B,temp);
    mat[poi]=Mul(mat[poi<<1], mat[poi<<1^1]);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,1,n);
        int p,x,y,z;
        for(int i=0; i<m; ++i)
        {
            scanf("%d",&p);
            if(p)
            {
                scanf("%d%d%d",&x,&y,&z);
                change(1,1,n,y-1,z-1,x);
            }
            else
            {
                scanf("%d%d",&x,&y);
                Mat temp=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=(ans+temp.a[i][j])%mod;
                printf("%I64d\n",ans);
            }
        }
    }
    return 0;
}

/*
5
2 5

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值