题意:相邻的两层楼之间有两个门,每个门内都有一个楼梯,分别通向上一层的两扇门。但是,门内的楼梯会转换状态。所有楼梯起始都是通的。在状态转后后,会从通变成不通,反之也可以。如果楼梯是不通的,那就不能从该楼梯到上一层。有以下两种操作: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;
}