題目:LINK
該層的兩個門到下一層的兩個門的開關狀態可以表示成一個2*2的矩陣1表示開0表示關,每次狀態的改變就是對應位置0->1, 1->0,對於查詢[a,b], 只要求出a到b-1的矩陣的乘積就可以了。
由於有改變和多次查詢,所以可以用線段樹進行維護,單點更新,區間查詢。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
typedef __int64 LL;
#define N 3
const LL mod = 1000000007;
#define M 50005
int n, m;
struct node {
LL mat[N][N];
};
node S[M<<2];
node mul(node a, node b) {
node ret;
memset(ret.mat, 0, sizeof(ret.mat));
for(int k = 1; k <= 2; k++) {
for(int i = 1; i <= 2; i++) {
for(int j = 1; j <= 2; j++) {
ret.mat[i][j] += a.mat[i][k] * b.mat[k][j];
ret.mat[i][j] %= mod;
}
}
}
return ret;
}
void pushup(int rt) {
S[rt] = mul(S[rt<<1], S[rt<<1|1]);
}
void build(int l, int r, int rt) {
if(l == r) {
S[rt].mat[1][1] = S[rt].mat[1][2] = S[rt].mat[2][1] = S[rt].mat[2][2] = 1;
return ;
}
int m = (l+r)>>1;
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
pushup(rt);
}
node query(int L,int R,int l, int r, int rt) {
if(L<=l && r<=R) {
return S[rt];
}
int m = (l+r)>>1;
node ret;
ret.mat[1][1] = ret.mat[2][2] = 1;
ret.mat[1][2] = ret.mat[2][1] = 0;
if(L <= m) ret = mul(ret, query(L, R, l, m, rt<<1));
if(R > m) ret = mul(ret, query(L, R, m+1, r, rt<<1|1));
return ret;
}
void updata(int a, int b, int c, int l, int r, int rt) {
if(l == r) {
S[rt].mat[b][c] = 1 - S[rt].mat[b][c];
return ;
}
int m = (l+r)>>1;
if(a <= m) updata(a, b, c, l, m, rt<<1);
else updata(a, b, c, m+1, r, rt<<1|1);
pushup(rt);
}
int main() {
while(scanf("%d%d", &n, &m) != EOF) {
build(1, n, 1);
for(int i = 1; i <= m; i++) {
int tmp;
scanf("%d", &tmp);
if(tmp == 0) {
int a, b;
scanf("%d%d", &a, &b);
node ans = query(a, b-1,1, n, 1);
LL out = 0;
for(int q = 1; q <= 2; q++) {
for(int j = 1; j <= 2; j ++) {
out += ans.mat[q][j];
out %= mod;
}
}
printf("%I64d\n", out);
}
else {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
updata(a, b, c, 1, n, 1);
}
}
}
return 0;
}