CF718C Sasha and Array
阿新 • • 發佈:2020-08-16
前言
一道打著很舒服的 線段樹 + 矩陣加速 的題
題目
講解
1e9範圍的斐波拉契數直接想到矩陣加速
而區間和就讓我們想到線段樹,用矩陣轉移
具體的,維護 \(f_{a[i]},f_{a[i+1]}\)與lazy矩陣 即可實現轉移
程式碼
//12252024832524 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 100005; const int MOD = 1e9 + 7; int n,m; int a[MAXN]; int Read() { int x = 0,f = 1;char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } void Put1(int x) { if(x > 9) Put1(x/10); putchar(x%10^48); } void Put(int x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } template <typename T>T Max(T x,T y){return x > y ? x : y;} template <typename T>T Min(T x,T y){return x < y ? x : y;} template <typename T>T Abs(T x){return x < 0 ? -x : x;} void AM(int &x,int y) { x += y; if(x >= MOD) x -= MOD; } struct Matrix { int n,m; int a[2][2]; Matrix(){memset(a,0,sizeof(a));} Matrix operator + (const Matrix C)const{ Matrix ret; ret.n = n;ret.m = m; for(int i = 0;i < n;++ i) for(int j = 0;j < m;++ j) AM(ret.a[i][j],C.a[i][j]),AM(ret.a[i][j],a[i][j]); return ret; } Matrix operator * (const Matrix C)const{ Matrix ret; ret.n = n;ret.m = C.m; for(int i = 0;i < n;++ i) for(int k = 0;k < m;++ k) if(a[i][k]) for(int j = 0;j < C.m;++ j) ret.a[i][j] = (ret.a[i][j] + 1ll * a[i][k] * C.a[k][j]) % MOD; return ret; } }I,A,B; Matrix qpow(Matrix di,Matrix x,int y) { Matrix ret = di; while(y) { if(y & 1) ret = ret * x; x = x * x; y >>= 1; } return ret; } int fib(int x) { if(x <= 1) return A.a[0][x]; else return qpow(A,B,x-1).a[0][1]; } struct SegmentTree { struct node { int l,r; Matrix val,lz; }t[MAXN << 2]; void update(int x) { t[x].val = t[x<<1].val + t[x<<1|1].val; } void down(int x) { t[x<<1].lz = t[x].lz * t[x<<1].lz; t[x<<1|1].lz = t[x].lz * t[x<<1|1].lz; t[x<<1].val = t[x<<1].val * t[x].lz; t[x<<1|1].val = t[x<<1|1].val * t[x].lz; t[x].lz = I; } void Add(int x,int l,int r,Matrix ad) { if(l <= t[x].l && t[x].r <= r) { t[x].lz = t[x].lz * ad; t[x].val = t[x].val * ad; return; } down(x); int mid = (t[x].l + t[x].r) >> 1; if(l <= mid) Add(x<<1,l,r,ad); if(mid+1 <= r) Add(x<<1|1,l,r,ad); update(x); } void Build(int x,int l,int r) { t[x].l = l;t[x].r = r; t[x].val.n = 1;t[x].val.m = 2; t[x].lz = I; if(l == r) { t[x].val.a[0][0] = fib(a[l]-1); t[x].val.a[0][1] = fib(a[l]); return; } int mid = (l+r) >> 1; Build(x<<1,l,mid); Build(x<<1|1,mid+1,r); update(x); } int query(int x,int l,int r) { if(l <= t[x].l && t[x].r <= r) return t[x].val.a[0][1]; down(x); int mid = (t[x].l + t[x].r) >> 1,ret = 0; if(l <= mid) AM(ret,query(x<<1,l,r)); if(mid+1 <= r) AM(ret,query(x<<1|1,l,r)); return ret; } }st; int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); I.n = I.m = 2; I.a[0][0] = I.a[1][1] = 1; A.n = 1;A.m = 2; A.a[0][0] = 0,A.a[0][1] = 1; B.n = B.m = 2; B.a[0][1] = B.a[1][1] = B.a[1][0] = 1; n = Read(); m = Read(); for(int i = 1;i <= n;++ i) a[i] = Read(); st.Build(1,1,n); while(m--) { int opt = Read(),l = Read(),r = Read(); if(opt == 1) st.Add(1,l,r,qpow(I,B,Read())); else Put(st.query(1,l,r),'\n'); } return 0; }