HDU 5068 Harry And Math Teacher 线段树维护矩阵乘积

来源:互联网 发布:荣威rx5发动机 知乎 编辑:程序博客网 时间:2024/06/02 00:24

题意:相邻的两层楼之间有两个门,每个门内都有一个楼梯,分别通向上一层的两扇门。但是,门内的楼梯会转换状态。所有楼梯起始都是通的。在状态转后后,会从通变成不通,反之也可以。如果楼梯是不通的,那就不能从该楼梯到上一层。有以下两种操作:1.修改X层第Y个门通向上一层的第Z个门的楼梯的状态。2.查询从第X层到第Y层的所有的方案数。

思路:因为查询的是方案数,我们想到了DP。但是,题目中的是动态修改动态查询,怎么办呢?因为是线性递推,我们可以利用矩阵来计算方案数。

            同时,因为矩阵满足结合律,我们就可以利用线段树来保存成段的矩阵乘积。而修改就是单点修改了。

注意:虽然题目中明确要求用取模运算,但是在计算的过程中还是会爆int的,所以要用long long.

代码如下:

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;typedef long long ll;const ll MOD = 1000000007;const int MAX = 50010;struct Matrix{    ll a[2][2];    Matrix(){memset(a,0,sizeof(a));}    Matrix operator * (const Matrix & A) const{        Matrix C;        for(int i = 0; i < 2; ++i)            for(int j = 0; j < 2; ++j)                for(int k = 0; k < 2; ++k)                    C.a[i][j] = (C.a[i][j] + a[i][k] * A.a[k][j]) % MOD;        return C;    }};#define lson(o) (o<<1)#define rson(o) ((o<<1)|1)struct yy{    Matrix m;    int l,r;} node[MAX<<3];void pushup(int o){    node[o].m = node[lson(o)].m * node[rson(o)].m;}void build(int l, int r, int o){    node[o].l = l;    node[o].r = r;    if(l == r){        for(int i = 0; i < 2; ++i)            for(int j = 0; j < 2; ++j)                node[o].m.a[i][j] = 1;        return;    }    int mid = (l + r) >>1;    build(l,mid,lson(o));    build(mid+1,r,rson(o));    pushup(o);}int x,y,z;void update(int x,int o){    if(node[o].l == node[o].r){        node[o].m.a[y][z] ^= 1;        return;    }    int mid = (node[o].l + node[o].r) >> 1;    if(x <= mid)        update(x,lson(o));    else        update(x,rson(o));    pushup(o);}Matrix query(int L,int R,int o){    if(L <= node[o].l && R >= node[o].r)        return node[o].m;    Matrix ans;    ans.a[0][0] = ans.a[1][1] = 1;    int mid = (node[o].l + node[o].r) >> 1;    if(L <= mid)        ans = ans * query(L,R,lson(o));    if(R > mid)        ans = ans * query(L,R,rson(o));    return ans;}int main(void){    //freopen("in","r",stdin);    int N,M;    while(~scanf("%d%d", &N,&M)){        build(1,N-1,1);        for(int i = 0; i < M; ++i){            int Q;            scanf("%d", &Q);            if(Q==1){                scanf("%d %d %d", &x,&y,&z);                y--,z--;                update(x,1);            }            else{                scanf("%d %d", &x,&y);                Matrix ret = query(x,y-1,1);                ll ans = 0;                for(int i = 0; i < 2; ++i)                    for(int j = 0; j < 2; ++j)                        ans = (ans + ret.a[i][j]) % MOD;                printf("%I64d\n",ans);            }        }    }    return 0;}


0 0
原创粉丝点击