被験者は、あなたが自分自身について考える必要があり、特に難しいことではない、私はこの方法を開始したい、いや、非常に複雑で、その後、LJは、行列の乗算を言う、そしてあなたが書く方法を知っているそれについて考えるために私を促しました。
これは、中に入るには、ツリーラインに直接行列です。
最適化に注意し、複雑さを軽減。
書式#include <CStringの> の#include <iostreamの> の#include <アルゴリズム> 書式#include <cstdioを> する#include <cstdlib> 書式#include <キュー> の#define INF 0x3f3f3f3f 使用して 名前空間はstd; typedefの長い 長いLL。 const int型 MOD = 1E9 + 7 。 構造体マット { LLのM [ 3 ] [ 3 ]。 }、ゼロ団結。 マット演算子 * (マットB、MAT){ マットANS。 以下のための(int型私は=1 ; iは<= 2 ; I ++ ){ ための(int型 J = 1 ; J <= 2、J ++ ){ LL、X = 0 。 用(INT K = 1 ; <= K 2 ++ k個;)x + =(AM [I] [K] * BM [K] [J])%MOD。 ans.m [I] [j]は、X%= MOD。 } } 戻りANS。 } マット演算子 + (マットB、MAT){ マットANS。 以下のために(int型 = Iを1 ; I <= 2; I ++ ) のための(INT J = 1 ; J <= 2、J ++ ) ans.m [I] [J] =(AM [I] [J] + BM [I] [J])%MOD。 戻るANSを。 } マットmod_pow(マットA、LL N){ マットANS = 団結。 一方、(N){ 場合(N - 1)ANS = ANS * 。 A * = 。 N >> = 1 。 } 戻りANS。 } のconst int型 MAXN = 1E5 + 10 。 マット和[MAXN* 4 ]、怠惰[MAXN * 4 ]。 ; [MAXN] V LL 無効INITを(){ アム[ 1 ] [ 1 ] =午前[ 1 ] [ 2 ] =午前[ 2 ] [ 1 ] = 1、午前[ 2 ] [ 2 ] = 0 ; 以下のために(int型 i = 0 ; iは< 3 ; iは++)unite.mを[I] [I] = 1 。 以下のために(int型 = Iを0 ; iは< 3 ; I ++ ) のための(INT J =0 ; J < 3 ; J ++)zero.m [I] [J] = 0 ; } ボイド push_up(int型のID){ 和[ID] =和[ID << 1 ] +和[ID << 1 | 1 ]。 } ボイドビルド(int型 ID、int型の L、INT R){ 怠惰[ID] = 団結。 もし(L == R){ 和[ID] = mod_pow(V [L])。 返します。 } INT半ば=(L + R)>> 1 。 構築(ID << 1、L、MID)。 構築(ID << 1 | 1、ミッド+ 1 、R); push_up(ID)。 } BOOL (マットB、MAT)と同じ{ ため(int型 i = 1 ; iが= < 2 ; iは++ ){ ため(int型の J = 1 ; J <= 2、J ++ ){ 場合(AM [I] [J] != BM [I] [J])を返す 偽。 } } 戻り 真。 } ボイド push_down(int型のID){ もし(同じ(怠惰[ID]は、)団結)を返します。 和[ID << 1 ] =和[idは<< 1 ] * 怠惰[ID]。 合計[ID << 1 | 1 ] =和[ID << 1 | 1 ] * ]怠惰[IDと、 怠惰[ID << 1 ]怠惰[IDを<< = 1 ] * 怠惰[ID]。 怠惰[ID << 1 | 1 ] =怠惰[ID << 1 | 1 ] * ]怠惰[IDと、 怠惰[ID] = 団結。 } ボイド更新(int型 ID、INTL、のint R、int型のx、int型のY、マットヴァル){ 場合(X <= L && Y> = {R) 怠惰[ID] =怠惰[ID] * ヴァル。 和[ID] =和[ID] * ヴァル。 返します。 } push_down(ID)。 INT半ば=(L + R)>> 1 。 もし(x <= MID)更新(ID << 1 、L、中、X、Y、ヴァル)。 もし(Y> MID)更新(ID << 1 | 1、中間+ 1 、R、X、Y、ヴァル)。 push_up(ID)。 } マットクエリ(int型 ID、INTL、のint R、int型のx、int型のY){ 場合(X <= L && Y> = r)は戻り和[ID]。 マットANS = ゼロ。 INT半ば=(L + R)>> 1 。 push_down(ID)。 もし(x <= MID)ANS = ANS +クエリ(ID << 1 、L、中、X、Y) もし(Y> MID)ANS = ANS +クエリ(ID << 1 | 1、中間+ 1 、R、X、Y)。 戻るANSを。 } int型のmain(){ INIT()。 INTのN、M。 scanf関数(" %d個の%のD "、&N、&M); 以下のために(int型 i = 1 ; iが<= N; iは++)scanf関数を(" %のLLD "、&V [I])。 ビルド(1、1 、N) 一方、(M-- ){ int型OPT。 LLのL、R、X。 scanf関数(" %d個"、&OPT)。 もし(OPTの== 1 ){ scanf関数(" %LLD%LLD%LLD "、&L&R&X)。 マットヴァル = mod_pow(X)。 アップデート(1、1 、N、L、R、ヴァル)。 } 他{ scanf関数(" %のLLDの%のLLD "、&L&R)。 マットANS =クエリ(1、1 、N、L、R)。 printf(" %LLDする\ n "、ans.m [ 1 ] [ 2 ])。 } } 戻り 0 。 }