Hdu--5068(线段树,矩阵乘法,思维精巧)

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 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4034103.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值