题解
帖题解:
我们可以把第i层跟第i+1层之间楼梯的通断性构造成一个2*2的通断性矩阵,1表示通,0表示不通。
那么从第a层到第b层,就是将a到b-1的通断性矩阵连乘起来,然后将得到的答案矩阵上的每个元素加起来即为方案数。
想到矩阵的乘法是满足结合律的,那么我们可以用线段树来维护矩阵的乘积。
每次我们只会修改某一个楼梯的通断性,所以就只是简单的线段树单点更新,成段求乘积而已。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N=1e6+10;
const int mod=1e9+7;
int n,m,k;
struct Mat{
ll a[2][2];
Mat operator*(const Mat& b)const{
Mat t={0,0,0,0};
for (int i = 0; i <2; ++i) {
for (int j = 0; j <2; ++j) {
for (int k = 0; k <2; ++k) {
t.a[i][j]=(t.a[i][j]+a[i][k]*b.a[k][j])%mod;
}
}
}
return t;
}
ll val(){
ll ans=0;
for (int i = 0; i <2; ++i) {
for (int j = 0; j <2; ++j) {
ans=(ans+a[i][j])%mod;
}
}
return ans;
}
}tree[N<<2];
void pushup(int rt){
tree[rt]=tree[rt<<1]*tree[rt<<1|1];
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]={1,1,1,1};
return;
}
int mid=l+r>>1;
build(lson);
build(rson);
pushup(rt);
}
void update(int x,int y,int z,int l,int r,int rt){
if(l==r){
tree[rt].a[y][z]^=1;//取反操作
return;
}
int mid=l+r>>1;
if(x<=mid)update(x,y,z,lson);
else update(x,y,z,rson);
pushup(rt);
}
Mat query(int x,int y,int l,int r,int rt){
if(x<=l && y>=r){
return tree[rt];
}
int mid=l+r>>1;
Mat res={1,0,0,1};//注意 是单位矩阵
if(x<=mid) res=res*query(x,y,lson);
if(y>mid) res=res*query(x,y,rson);
return res;
}
int op;
int main(){
while(cin>>n>>m){
build(1,n,1);
for (int i = 1,a,b,x,y,z; i <= m; ++i) {
cin>>op;
if(op==0){
cin>>a>>b;
b--;
Mat ans=query(a,b,1,n,1);
cout<<ans.val()<<endl;
}else{
cin>>x>>y>>z;
y--;z--;
update(x,y,z,1,n,1);
}
}
}
return 0;
}