hdu-5068 Harry And Math Teacher

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

题意:给你n层楼,每层楼有两个门,

m个操作 Q = 1  表示 第 x 层楼 第y个门到第x+1层楼的第z个门的路改变其状态(初始每条路都可以走的)

*            Q = 0   表示询问第x层楼到第y层楼的方式有多少种

题解:线段数 + 矩阵乘法       

因为只有两个门所以我们可以把第x层楼到第x+1层楼标记状态

/**单纯的从某层楼到某层楼,可以用一个递推,然后可以演化成矩阵如下
 *   0 1
 *  ————
 *0 |1 1
 *1 |1 1
 *如果在更新的话只需更改某个门到某个门的标记即可,即异或1,就可以改变其状态,即矩阵的值有所改变;
 *此题比较裸地线段树(插点问线问题)
 *根据矩阵的结合律计算即可
**/#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef __int64 LL;
const LL  mod = 1000000007;
#define M 50010
#define lson(st) (st<<1)
#define rson(st) ((st<<1)|1)
int x,y,z;
struct matrix{
    LL m[2][2];
    matrix(){memset(m,0,sizeof(m));}
    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.m[i][j] = (c.m[i][j] + m[i][k]*a.m[k][j]) % mod;
        return c;
    }
};
struct Node{
    matrix s;
    int l,r;
}node[M<<3];
void Pushup(int st){
    node[st].s= node[lson(st)].s * node[rson(st)].s;
}
void build(int l,int r,int st){
    node[st].l = l;
    node[st].r = r;
    if(l == r){
        for(int i = 0;i < 2;i++)
            for(int j = 0;j < 2;j++)
                node[st].s.m[i][j] = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    build(l,mid,lson(st));
    build(mid+1,r,rson(st));
    Pushup(st);
}
void update(int x,int st){
    if(node[st].l == node[st].r){
        node[st].s.m[y][z] ^= 1;
        return ;
    }
    int mid = (node[st].l + node[st].r) >> 1;
    if(x <= mid) update(x,lson(st));
    else update(x,rson(st));
    Pushup(st);
}
matrix Query(int L,int R,int st){
    if(node[st].l >= L && node[st].r <= R)
        return node[st].s;
    matrix ans;
    ans.m[0][0] = ans.m[1][1] = 1;
    int mid = (node[st].l + node[st].r) >> 1;
    if(L <= mid) ans = ans * Query(L,R,lson(st));
    if(R > mid)  ans = ans * Query(L,R,rson(st));
    return ans;
}
int main()
{
    int n,m,q;
    while(~scanf("%d%d",&n,&m)){
        build(1,n-1,1);
        for(int i = 0;i < m;i++){
            cin >> q;
            if(q == 1)
            {
                cin >> x >> y >> z;
                y--,z--;
                update(x,1);
            }
            else {
                cin >> x >> y;
                matrix res = Query(x,y-1,1);
                LL ans = 0;
                for(int k = 0;k < 2;k++)
                    for(int j = 0;j < 2;j++)
                        ans = (ans + res.m[k][j]) % mod;
                cout << ans << endl;
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值