codeforces #373(div 2) E (线段树+矩阵快速幂)

来源:互联网 发布:vb编程入门视频教程 编辑:程序博客网 时间:2024/05/22 14:25
C. Sasha and Array
time limit per test
5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Sasha has an array of integers a1, a2, ..., an. You have to performm queries. There might be queries of two types:

  1. 1 l r x — increase all integers on the segment froml tor by valuesx;
  2. 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?

Input

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.

Output

For each query of the second type print the answer modulo 109 + 7.

Examples
Input
5 41 1 2 1 12 1 51 2 4 22 2 42 1 5
Output
579
Note

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.


题意:

给一个数组a,有两个操作

1.在l到r区间上对a数组中元素ai全部加x。

2.对l到r上的元素求出f(ai)的和。f(ai)为第ai个斐波那契数,f(1)=1,f(2)=1,f(3)=2.....


思路:

题目很明显是用线段树解决,但是因为斐波那契数列的原因无法直接套线段树。

斐波那契的递推公式是f(n)=f(n-1)+f(n-2),由此可以用矩阵 [1,1] 表示。

                                                                                                             [1,0]

区间相加的也可以通过对区间和乘以斐波那契矩阵的x次方来解决。

运用矩阵快速幂的话能将复杂度控制在lgn的效率,最后ac代码运行时间为2s


#include<iostream> #include<stdio.h> #include<math.h> #include<string.h> #include<vector> #include<queue> #include<map> #include<stack> #include<queue> #include<algorithm> using namespace std; const int mod=1e9+7;struct mat{long long mm[2][2];int flag;mat(){memset(mm,0,sizeof(mm));flag=0;}void init(){for(int i=0;i<2;i++)for(int j=0;j<2;j++){if(i==j)mm[i][j]=1;else mm[i][j]=0;}flag=0;        }mat operator + (const mat &b)const//矩阵相加{mat c;for(int i=0;i<2;i++)for(int j=0;j<2;j++)c.mm[i][j]=(mm[i][j]+b.mm[i][j])%mod;return c;}mat operator * (const mat &b)const{mat c;memset(c.mm,0,sizeof(c.mm));for(int i=0;i<2;i++)//矩阵相乘for(int j=0;j<2;j++)for(int k=0;k<2;k++)c.mm[i][j]=(c.mm[i][j]+mm[i][k]*b.mm[k][j])%mod;return c;}mat operator ^ (const int &t)const//矩阵快速幂{mat a,res;res.init();int p=t;a.mm[0][1]=a.mm[0][0]=a.mm[1][0]=1;a.mm[1][1]=0;while(p){if(p&1)res=res*a;a=a*a;p>>=1;}return res;}};const int N=100005;mat sumtree[N*4+10],mark[N*4+10];int a[N+10];void build(int start,int end,int node){mark[node].init();    if(start==end)    {sumtree[node].init();sumtree[node]=sumtree[node]^(a[start]-1);return;}    build(start,(start+end)/2,node*2);    build((start+end)/2+1,end,node*2+1);sumtree[node]=sumtree[node*2]+sumtree[node*2+1];}void changetree(int node,mat nn,int start,int end,int left,int right)//运用延迟数组对线段树进行维护{    if(right>=end&&left<=start){sumtree[node]=sumtree[node]*nn;mark[node]=mark[node]*nn;mark[node].flag=1;return;}if(mark[node].flag!=0){mark[node*2]=mark[node*2]*mark[node];mark[node*2].flag=1;mark[node*2+1]=mark[node*2+1]*mark[node];mark[node*2+1].flag=1;sumtree[node*2]=sumtree[node*2]*mark[node];sumtree[node*2+1]=sumtree[node*2+1]*mark[node];mark[node].init();}int m=(start+end)/2;if(left<=m) changetree(node*2,nn,start,m,left,right);if(right>m) changetree(node*2+1,nn,m+1,end,left,right);sumtree[node]=sumtree[node*2]+sumtree[node*2+1];}long long searchsum(int node,int start,int end,int left,int right){ if(left<=start&&right>=end)return sumtree[node].mm[0][0];if(mark[node].flag!=0){mark[node*2]=mark[node*2]*mark[node];mark[node*2].flag=1;mark[node*2+1]=mark[node*2+1]*mark[node];mark[node*2+1].flag=1;sumtree[node*2]=sumtree[node*2]*mark[node];sumtree[node*2+1]=sumtree[node*2+1]*mark[node];mark[node].init();}    int mid=(start+end)/2;    long long sum=0;    if(left<=mid) sum=(sum+searchsum(node*2,start,mid,left,right))%mod;    if(right>mid) sum=(sum+searchsum(node*2+1,mid+1,end,left,right))%mod;    return sum;}int main(){    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);int n,m;scanf("%d%d",&n,&m);mat base;base.init();for(int i=0;i<n;i++){scanf("%d",&a[i]);}build(0,n-1,1);while(m--){int type,l,r;scanf("%d%d%d",&type,&l,&r);if(type==1){int xx;scanf("%d",&xx);changetree(1,base^(xx),0,n-1,l-1,r-1);}else printf("%lld\n",(searchsum(1,0,n-1,l-1,r-1))%mod);}    return 0;}


0 0
原创粉丝点击