CodeForces 718C Sasha and Array(矩阵类+线段树)
来源:互联网 发布:golang 代码安全 泄密 编辑:程序博客网 时间:2024/06/13 23:24
Sasha has an array of integers a1, a2, ..., an. You have to perform m queries. There might be queries of two types:
- 1 l r x — increase all integers on the segment froml to r by valuesx;
- 2 l r — find , wheref(x) is the x-th Fibonacci number. As this number may be large, you only have to find it modulo109 + 7.
In this problem we define Fibonacci numbers as follows: f(1) = 1, f(2) = 1, f(x) = f(x - 1) + f(x - 2) for allx > 2.
Sasha is a very talented boy and he managed to perform all queries in five seconds. Will you be able to write the program that performs as well as Sasha?
The first line of the input contains two integers n andm (1 ≤ n ≤ 100 000,1 ≤ m ≤ 100 000) — the number of elements in the array and the number of queries respectively.
The next line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109).
Then follow m lines with queries descriptions. Each of them contains integerstpi,li,ri and may bexi (1 ≤ tpi ≤ 2,1 ≤ li ≤ ri ≤ n,1 ≤ xi ≤ 109). Heretpi = 1 corresponds to the queries of the first type andtpi corresponds to the queries of the second type.
It's guaranteed that the input will contains at least one query of the second type.
For each query of the second type print the answer modulo 109 + 7.
5 41 1 2 1 12 1 51 2 4 22 2 42 1 5
579
Initially, array a is equal to 1, 1, 2, 1, 1.
The answer for the first query of the second type is f(1) + f(1) + f(2) + f(1) + f(1) = 1 + 1 + 1 + 1 + 1 = 5.
After the query 1 2 4 2 array a is equal to 1, 3, 4, 3, 1.
The answer for the second query of the second type is f(3) + f(4) + f(3) = 2 + 3 + 2 = 7.
The answer for the third query of the second type is f(1) + f(3) + f(4) + f(3) + f(1) = 1 + 2 + 3 + 2 + 1 = 9.
虽然说矩阵快速幂不是本题的主要算法,但在这题却发挥着举足轻重的作用。
大致题意就是,给出一组数列,有区间加和区间求和两种操作。但是不同的是,这里的求和不是单纯的数字相加,而是Fibonacci数列的第ai项,即Fibonacci数列对应项的总和。如果用普通的区间更新,增加操作非常简单,但是区间的Fibonacci数列对应项之和却不好求。这个时候矩阵就派上了用场。
我们知道,FIbonacci数列的第i项可以通过矩阵快速幂求得,而矩阵既有乘法也有加法,所以既可以做到修改,也可以做到求和。修改的话,对于一个区间其对应项数加x,相当于整个区间乘以转移矩阵x次方。而求和的话,就是直接维护矩阵之和。如此一来,线段树中的和sum、lazytag,这些都得是矩阵类型的,然后会涉及到加、乘和乘方,故我们直接把矩阵写成一个矩阵类,使得程序更加的美观。纯线段树代码部分几乎看不出与普通的有什么区别。这里要注意因为修改做的是乘法的修改,所以初始化lazy和lazy下传之后,lazy不是变成0,而是变成单位矩阵。具体细节见代码:
#include<iostream>#include<cstdio>#include<algorithm>#include<cstdlib>#include<cstring>#include<cmath>#include<iomanip>#include<vector>#include<queue>#define LL long long#define N (int) 1e5+10#define mod 1000000007using namespace std;struct matrix//矩阵类,包含加法、乘法、乘方{LL a[3][3];void init(){for(int i=1;i<3;i++)for(int j=1;j<3;j++)a[i][j]=0;}friend matrix operator *(matrix x,matrix y) { matrix res; res.init(); for(int i=1;i<3;i++) for(int j=1;j<3;j++) { for(int k=1;k<3;k++) res.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod; res.a[i][j]%=mod; } return res; } friend matrix operator ^(matrix x,LL y) { matrix res; if (y==0) { for(int i=1;i<3;i++) for(int j=1;j<3;j++) res.a[i][j]=0; for(int i=1;i<3;i++) res.a[i][i]=1; return res; } else while ((y&1)==0) {y>>=1;x=x*x;} res=x; y>>=1; while (y!=0) { x=x*x; if ((y&1)!=0) res=res*x; y>>=1; } return res; } friend matrix operator +(matrix x,matrix y) { matrix res; for(int i=1;i<3;i++) for(int j=1;j<3;j++) res.a[i][j]=(x.a[i][j]+y.a[i][j])%mod; return res; } friend bool operator !=(matrix x,matrix y) { for(int i=1;i<3;i++) for(int j=1;j<3;j++) if (x.a[i][j]!=y.a[i][j]) return 1; return 0; }} x,basic;int a[N],n,m;struct ST{struct node{matrix sum,lazy;int l,r;} tree[N<<2];inline void push_up(int i){tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;//区间Fibonacci数列和}inline void build(int i,int l,int r){tree[i].r=r;tree[i].l=l;tree[i].lazy=basic;//初始化为单位矩阵if (l==r){ tree[i].sum=x^(a[l]-1);//初始值return;}LL mid=(l+r)>>1;build(i<<1,l,mid);build(i<<1|1,mid+1,r);push_up(i);}inline void push_down(int i){tree[i<<1].lazy=tree[i<<1].lazy*tree[i].lazy;tree[i<<1|1].lazy=tree[i<<1|1].lazy*tree[i].lazy;//lazy是以乘法下传tree[i<<1].sum=tree[i<<1].sum*tree[i].lazy;tree[i<<1|1].sum=tree[i<<1|1].sum*tree[i].lazy;tree[i].lazy=basic;//下传后初始化为基本矩阵}inline void update(int i,int l,int r,matrix x){if ((tree[i].l==l)&&(tree[i].r==r)){tree[i].sum=tree[i].sum*x;tree[i].lazy=tree[i].lazy*x;return;}if (tree[i].lazy!=basic) push_down(i);LL mid=(tree[i].l+tree[i].r)>>1;if (mid>=r) update(i<<1,l,r,x);else if (mid<l) update(i<<1|1,l,r,x);else{update(i<<1,l,mid,x);update(i<<1|1,mid+1,r,x);}push_up(i);}inline matrix getsum(int i,int l,int r){if ((tree[i].l==l)&&(tree[i].r==r)) return tree[i].sum;if (tree[i].lazy!=basic) push_down(i);LL mid=(tree[i].l+tree[i].r)>>1;if (mid>=r) return getsum(i<<1,l,r);else if (mid<l) return getsum(i<<1|1,l,r);else return getsum(i<<1,l,mid)+getsum(i<<1|1,mid+1,r);}} seg;int main(){ x.a[1][1]=1; x.a[1][2]=1; x.a[2][1]=1; basic.a[1][1]=basic.a[2][2]=1;//初始化转移矩阵和基本矩阵 while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); seg.build(1,1,n); while(m--) { int l,r,op,delta; scanf("%d%d%d",&op,&l,&r); if (op==1) { scanf("%d",&delta); seg.update(1,l,r,x^delta);//每次区间乘上转移矩阵的delta次方 } else { matrix ans=seg.getsum(1,l,r); printf("%lld\n",ans.a[1][1]); } } } return 0;}
- Codeforces 718C Sasha and Array(线段树维护矩阵)
- CodeForces 718C Sasha and Array(矩阵类+线段树)
- codeforces 373div1 Sasha and Array 矩阵+线段树
- 【Codeforces 718C&719E】Sasha and Array【线段树成段更新+矩阵快速幂】
- Codeforces 718C C. Sasha and Array
- cf/Codeforces Round #373 div1-C/div2-E Sasha and Array 线段树 + 维护矩阵快速幂
- codeforces 718 C.Sasha and Array
- codeforces 718C - Sasha and Array
- [题解]codeforces 718c Sasha and Array
- [Codeforces 719 E. Sasha and Array] 矩阵快速幂+线段树
- CodeForces-719E Sasha and Array(线段树+矩阵快速幂)
- 【CodeForces 719E】【线段树+矩阵快速幂】 Sasha and Array
- Codeforces Round #373 (Div. 2) E. Sasha and Array 线段树维护矩阵
- CodeForces 719E Sasha and Array 【线段树】【快速矩阵幂】
- CodeForces - 719E Sasha and Array 线段树 + 矩阵快速幂
- 线段树+矩阵快速幂 codeforces718C Sasha and Array
- E. Sasha and Array——矩阵+线段树
- [codeforces] 719E Sasha and Array 线段树+快速斐波那契
- 2017年7月21日
- httpRequest函数
- POJ2566 尺取法巧解
- JAVA 三元运算符
- 正儿八经第一次应聘安卓开发的经历
- CodeForces 718C Sasha and Array(矩阵类+线段树)
- 对于字典序排列的进一步简化
- 1.对象导论
- CF—822B Crossword solving
- CentOS打开关闭端口
- hdu1816Get Luffy Out * (2-sat)
- 封锁阳光大学【二分图染色】洛谷P1330
- ubuntu16.04下安装qtcreator
- 分数化小数(decimal)