本苟蒻第一次写题解,有不对的地方希望大家能够指出。
题目链接 Sasha and Array
题意:给定n个元素,每次可以进行两种操作
1.将[l,r]元素均增加x
2.求 f(x)代表斐波那契数列中第x个元素的值
题解:看到区间修改首先想到线段树,对于第二个操作,我们可以考虑矩阵加速,对于线段树每个区间,我们维护一个矩阵表示区间和的当前以及后继状态,懒标记也用一个矩阵表示(实际上也可以用一个数维护幂次,但取余时会比较复杂),懒标记下沉时可以直接表示为矩阵相乘,合并时因为是求和所以表示为矩阵相加。
细节可见代码注释
注:矩阵部分建议写成一整个结构体。
#include<iostream>
#include<stack>
#include<list>
#include<set>
#include<vector>
#include<algorithm>
#include<math.h>
#include<numeric>
#include<map>
#include<cstring>
#include<queue>
#include<iomanip>
#include<cmath>
#include<queue>
#include <bitset>
#include<unordered_map>
#ifndef local
#define endl '\n'
#endif */
#define mkp make_pair
using namespace std;
using std::bitset;
typedef long long ll;
typedef long double ld;
const int inf=0x3f3f3f3f;
const ll MAXN=2e6+10;
const ll N=1e5+100;
const ll mod=1e9+7;
const ll hash_p1=1610612741;
const ll hash_p2=805306457;
const ll hash_p3=402653189;
//-----------------------------------------------------------------------------------------------------------------*/
// ll head[MAXN],net[MAXN],to[MAXN],edge[MAXN]/*流量*/,cost[MAXN]//费用;
/*
void add(ll u,ll v,ll w,ll s){
to[++cnt]=v;net[cnt]=head[u];edge[cnt]=w;cost[cnt]=s;head[u]=cnt;
to[++cnt]=u;net[cnt]=head[v];edge[cnt]=0;cost[cnt]=-s;head[v]=cnt;
}
struct elemt{
int p,v;
};
struct comp{
public:
bool operator()(elemt v1,elemt v2){
return v1.v<v2.v;
}
};
-----------------------------------
求[1,MAXN]组合式和逆元
ll mi(ll a,ll b){
ll res=1;
while(b){
if(b%2){
res=res*a%mod;
}
a=a*a%mod;
}
return res;
}
ll fac[MAXN],inv[MAXN]
fac[0]=1;inv[0]=1;
for(int i=1;i<=MAXN;i){
fac[i]=(fac[i-1]*i)%mod;
inv[i]=mi(fac[i],mod-2);
}
ll C(int m,int n){//组合式C(m,n);
if(!n){
return 1;
}
return fac[m]*(inv[n]*inv[m*-n]%mod)%mod;
}
---------------------------------
unordered_map<int,int>mp;
//优先队列默认小顶堆 , greater<int> --小顶堆 less<int> --大顶堆
priority_queue<elemt,vector<elemt>,comp>q;
set<int>::iterator it=st.begin();
*/
// vector<vector<int>>edge; 二维虚拟储存坐标
//-----------------------------------------------------------------------------------------------------------------*/
//map<int,bool>mp[N];
const int len=2;//矩阵大小
struct square{
ll m[3][3];
void clear(){//清空矩阵
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
m[i][j]=0;
}
}
}
void init(){//初始化,根据具体题意确定(这默认单位矩阵)
for(int i=0;i<len;i++){
m[i][i]=1;
}
}
void print(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
cout<<"i="<<i<<" j="<<j<<" m="<<m[i][j]<<endl;
}
}
}
bool empty(){//判断是否为单位矩阵
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(m[i][j]&&i!=j||m[i][j]!=1&&i==j){
return 0;
}
}
}
return 1;
}
square operator*(const square &y)const{//矩阵乘法
square z;z.clear();
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
for(int k=0;k<len;k++){
z.m[i][j]=(z.m[i][j]+m[i][k]*y.m[k][j]%mod)%mod;
}
}
}
return z;
}
friend square operator+(square a,square b){
square z;z.clear();
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
z.m[i][j]=(a.m[i][j]+b.m[i][j])%mod;
}
}
return z;
}
};
int a[N];
square f;//递推矩阵
/*
1 1
1 0
*/
square base;//初始矩阵 ,m[1][1](i)代表当前
/*
3 (i+2) 2 (i+1)
2 (i+1) 1 (i)
*/
square mi(square a,ll b){//矩阵快速幂
square res;res.clear();res.init();
while(b){
if(b%2){
res=res*a;
}
a=a*a;
b/=2;
}
return res;
}
square t[4*N];
square lz[4*N];//懒标记为矩阵,可以不用担心取模的细节
void pushup(int rt){
t[rt]=t[2*rt]+t[2*rt+1];
}
void build(int l,int r,int rt){
t[rt].clear();
lz[rt].clear();
lz[rt].init();
if(l==r){
t[rt]=base*mi(f,a[l]-1);
return ;
}
int mid=(l+r)/2;
build(l,mid,2*rt);
build(mid+1,r,2*rt+1);
pushup(rt);
}
void pushdown(int rt){//懒标记下沉
if(t[rt].empty()){//为单位矩阵,说明无下沉标记
return ;
}
t[2*rt]=t[2*rt]*lz[rt];
t[2*rt+1]=t[2*rt+1]*lz[rt];
lz[2*rt]=lz[2*rt]*lz[rt];
lz[2*rt+1]=lz[2*rt+1]*lz[rt];
lz[rt].clear();
lz[rt].init();
}
void update(int l,int r,int le,int ri,int rt,int x){
if(le<=l&&ri>=r){
t[rt]=t[rt]*mi(f,x);
lz[rt]=lz[rt]*mi(f,x);
return ;
}
pushdown(rt);
int mid=(l+r)/2;
if(le<=mid){
update(l,mid,le,ri,2*rt,x);
}
if(ri>mid){
update(mid+1,r,le,ri,2*rt+1,x);
}
pushup(rt);
}
square query(int l,int r,int le,int ri,int rt){
square res;res.clear();
if(le<=l&&ri>=r){
return t[rt];
}
pushdown(rt);
int mid=(l+r)/2;
if(le<=mid){
res=res+query(l,mid,le,ri,2*rt);
}
if(ri>mid){
res=res+query(mid+1,r,le,ri,2*rt+1);
}
return res;
}
int main(){
/*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
/*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
f.clear();base.clear();
f.m[0][0]=f.m[0][1]=f.m[1][0]=1; //此部分为初始化初始矩阵
base.m[0][0]=2;base.m[0][1]=base.m[1][0]=base.m[1][1]=1;
//------------------------------------------------------------------数据录入
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
//--------------------------------------------------------------------
build(1,n,1);
while(m--){
int k,l,r,x;
cin>>k;
if(k==1){
cin>>l>>r>>x;
update(1,n,l,r,1,x);
}
else{
cin>>l>>r;
cout<<query(1,n,l,r,1).m[1][1]<<endl;
}
}
return 0;
}