2014-10-19 00:01:58
思路:比赛时只知道要用到线段树,但不知道怎么解决计数问题QAQ。看了题解幡然醒悟,果断1A。
这个巧妙的方法就是利用矩阵来计数,用2*2的矩阵来存门与门之间的连通情况,然后我们发现两个矩阵相乘后矩阵内数的和的含义就是所要计的数。
矩阵的行表示从哪个门出发,列表示到达哪个门。
比如:1 1 * 1 1 = 2 2就表示两排全连通的楼梯能构成的路径数:2+2+2+2 = 8条。
1 1 1 1 2 2
1 /************************************************************************* 2 > File Name: 1003.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Sat 18 Oct 2014 07:54:14 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 const int maxn = 50010; 27 const ll mod = 1000000007; 28 29 int n,m; 30 31 inline int Read(){ 32 int x = 0; 33 char c; 34 while(c < '0' || c > '9') c = getchar(); 35 while(c >= '0' && c <= '9'){ 36 x = x * 10 + c - '0'; 37 c = getchar(); 38 } 39 return x; 40 } 41 42 struct Mx{ 43 ll a[2][2]; 44 void clear(){ memset(a,0,sizeof(a));} 45 void stand(){ memset(a,0,sizeof(a)); for(int i = 0; i < 2; ++i) a[i][i] = 1;} 46 Mx operator * (Mx b){ 47 Mx c; 48 c.clear(); 49 for(int i = 0; i < 2; ++i) 50 for(int j = 0; j < 2; ++j) 51 for(int k = 0; k < 2; ++k){ 52 c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j]) % mod; 53 } 54 return c; 55 } 56 }g[maxn << 2]; 57 58 void Push_up(int p){ 59 g[p] = g[lp] * g[rp]; 60 } 61 62 void Build_tree(int p,int l,int r){ 63 if(l == r){ 64 g[p].a[0][0] = 1; 65 g[p].a[0][1] = 1; 66 g[p].a[1][0] = 1; 67 g[p].a[1][1] = 1; 68 return; 69 } 70 int mid = getmid(l,r); 71 Build_tree(lp,l,mid); 72 Build_tree(rp,mid + 1,r); 73 Push_up(p); 74 } 75 76 Mx Query_tree(int a,int b,int p,int l,int r){ 77 if(a <= l && r <= b){ 78 return g[p]; 79 } 80 int mid = getmid(l,r); 81 Mx tmp; 82 tmp.stand(); 83 if(a <= mid) tmp = tmp * Query_tree(a,b,lp,l,mid); 84 if(b > mid) tmp = tmp * Query_tree(a,b,rp,mid + 1,r); 85 return tmp; 86 } 87 88 void Update(int a,int b,int c,int p,int l,int r){ 89 if(l == r){ 90 g[p].a[b - 1][c - 1] ^= 1; 91 return; 92 } 93 int mid = getmid(l,r); 94 if(a <= mid) Update(a,b,c,lp,l,mid); 95 else Update(a,b,c,rp,mid + 1,r); 96 Push_up(p); 97 } 98 99 int main(){ 100 int op,a,b,c; 101 while(scanf("%d%d",&n,&m) != EOF){ 102 Build_tree(1,1,n - 1); 103 for(int i = 1; i <= m; ++i){ 104 op = Read(),a = Read(),b = Read(); 105 if(op == 0){ 106 Mx t = Query_tree(a,b - 1,1,1,n - 1); 107 ll ans = (t.a[0][0] + t.a[0][1] + t.a[1][0] + t.a[1][1]) % mod; 108 printf("%I64d\n",ans); 109 } 110 else{ 111 c = Read(); 112 Update(a,b,c,1,1,n - 1); 113 } 114 } 115 } 116 return 0; 117 }